#include "sqlite3.h"
#include "os_setup.h"
#if SQLITE_OS_WIN
# include "os_win.h"
#endif
#include <string.h>
#include <assert.h>
#define INST_MAX_PATHNAME 512
#define OS_ACCESS 1
#define OS_CHECKRESERVEDLOCK 2
#define OS_CLOSE 3
#define OS_CURRENTTIME 4
#define OS_DELETE 5
#define OS_DEVCHAR 6
#define OS_FILECONTROL 7
#define OS_FILESIZE 8
#define OS_FULLPATHNAME 9
#define OS_LOCK 11
#define OS_OPEN 12
#define OS_RANDOMNESS 13
#define OS_READ 14
#define OS_SECTORSIZE 15
#define OS_SLEEP 16
#define OS_SYNC 17
#define OS_TRUNCATE 18
#define OS_UNLOCK 19
#define OS_WRITE 20
#define OS_SHMUNMAP 22
#define OS_SHMMAP 23
#define OS_SHMLOCK 25
#define OS_SHMBARRIER 26
#define OS_ANNOTATE 28
#define OS_NUMEVENTS 29
#define VFSLOG_BUFFERSIZE 8192
typedef struct VfslogVfs VfslogVfs;
typedef struct VfslogFile VfslogFile;
struct VfslogVfs {
sqlite3_vfs base;
sqlite3_vfs *pVfs;
int iNextFileId;
sqlite3_file *pLog;
sqlite3_int64 iOffset;
int nBuf;
char aBuf[VFSLOG_BUFFERSIZE];
};
struct VfslogFile {
sqlite3_file base;
sqlite3_file *pReal;
sqlite3_vfs *pVfslog;
int iFileId;
};
#define REALVFS(p) (((VfslogVfs *)(p))->pVfs)
static int vfslogClose(sqlite3_file*);
static int vfslogRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int vfslogWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int vfslogTruncate(sqlite3_file*, sqlite3_int64 size);
static int vfslogSync(sqlite3_file*, int flags);
static int vfslogFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int vfslogLock(sqlite3_file*, int);
static int vfslogUnlock(sqlite3_file*, int);
static int vfslogCheckReservedLock(sqlite3_file*, int *pResOut);
static int vfslogFileControl(sqlite3_file*, int op, void *pArg);
static int vfslogSectorSize(sqlite3_file*);
static int vfslogDeviceCharacteristics(sqlite3_file*);
static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags);
static int vfslogShmMap(sqlite3_file *pFile,int,int,int,volatile void **);
static void vfslogShmBarrier(sqlite3_file*);
static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag);
static int vfslogOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int vfslogDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int vfslogAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int vfslogFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
static void *vfslogDlOpen(sqlite3_vfs*, const char *zFilename);
static void vfslogDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
static void vfslogDlClose(sqlite3_vfs*, void*);
static int vfslogRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int vfslogSleep(sqlite3_vfs*, int microseconds);
static int vfslogCurrentTime(sqlite3_vfs*, double*);
static int vfslogGetLastError(sqlite3_vfs*, int, char *);
static int vfslogCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static sqlite3_vfs vfslog_vfs = {
1,
sizeof(VfslogFile),
INST_MAX_PATHNAME,
0,
0,
0,
vfslogOpen,
vfslogDelete,
vfslogAccess,
vfslogFullPathname,
vfslogDlOpen,
vfslogDlError,
vfslogDlSym,
vfslogDlClose,
vfslogRandomness,
vfslogSleep,
vfslogCurrentTime,
vfslogGetLastError,
vfslogCurrentTimeInt64
};
static sqlite3_io_methods vfslog_io_methods = {
2,
vfslogClose,
vfslogRead,
vfslogWrite,
vfslogTruncate,
vfslogSync,
vfslogFileSize,
vfslogLock,
vfslogUnlock,
vfslogCheckReservedLock,
vfslogFileControl,
vfslogSectorSize,
vfslogDeviceCharacteristics,
vfslogShmMap,
vfslogShmLock,
vfslogShmBarrier,
vfslogShmUnmap
};
#if SQLITE_OS_UNIX && !defined(NO_GETTOD)
#include <sys/time.h>
static sqlite3_uint64 vfslog_time(){
struct timeval sTime;
gettimeofday(&sTime, 0);
return sTime.tv_usec + (sqlite3_uint64)sTime.tv_sec * 1000000;
}
#elif SQLITE_OS_WIN
#include <time.h>
static sqlite3_uint64 vfslog_time(){
FILETIME ft;
sqlite3_uint64 u64time = 0;
GetSystemTimeAsFileTime(&ft);
u64time |= ft.dwHighDateTime;
u64time <<= 32;
u64time |= ft.dwLowDateTime;
return u64time /(sqlite3_uint64)10;
}
#else
static sqlite3_uint64 vfslog_time(){
return 0;
}
#endif
static void vfslog_call(sqlite3_vfs *, int, int, sqlite3_int64, int, int, int);
static void vfslog_string(sqlite3_vfs *, const char *);
static int vfslogClose(sqlite3_file *pFile){
sqlite3_uint64 t;
int rc = SQLITE_OK;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
if( p->pReal->pMethods ){
rc = p->pReal->pMethods->xClose(p->pReal);
}
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0);
return rc;
}
static int vfslogRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst);
return rc;
}
static int vfslogWrite(
sqlite3_file *pFile,
const void *z,
int iAmt,
sqlite_int64 iOfst
){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst);
return rc;
}
static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xTruncate(p->pReal, size);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size);
return rc;
}
static int vfslogSync(sqlite3_file *pFile, int flags){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xSync(p->pReal, flags);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0);
return rc;
}
static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize);
return rc;
}
static int vfslogLock(sqlite3_file *pFile, int eLock){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xLock(p->pReal, eLock);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0);
return rc;
}
static int vfslogUnlock(sqlite3_file *pFile, int eLock){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0);
return rc;
}
static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0);
return rc;
}
static int vfslogFileControl(sqlite3_file *pFile, int op, void *pArg){
VfslogFile *p = (VfslogFile *)pFile;
int rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
if( op==SQLITE_FCNTL_VFSNAME && rc==SQLITE_OK ){
*(char**)pArg = sqlite3_mprintf("vfslog/%z", *(char**)pArg);
}
return rc;
}
static int vfslogSectorSize(sqlite3_file *pFile){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xSectorSize(p->pReal);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0);
return rc;
}
static int vfslogDeviceCharacteristics(sqlite3_file *pFile){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0);
return rc;
}
static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0);
return rc;
}
static int vfslogShmMap(
sqlite3_file *pFile,
int iRegion,
int szRegion,
int isWrite,
volatile void **pp
){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, rc, 0, 0);
return rc;
}
static void vfslogShmBarrier(sqlite3_file *pFile){
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
p->pReal->pMethods->xShmBarrier(p->pReal);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, SQLITE_OK, 0, 0);
}
static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
t = vfslog_time();
rc = p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
t = vfslog_time() - t;
vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, rc, 0, 0);
return rc;
}
static int vfslogOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
int rc;
sqlite3_uint64 t;
VfslogFile *p = (VfslogFile *)pFile;
VfslogVfs *pLog = (VfslogVfs *)pVfs;
pFile->pMethods = &vfslog_io_methods;
p->pReal = (sqlite3_file *)&p[1];
p->pVfslog = pVfs;
p->iFileId = ++pLog->iNextFileId;
t = vfslog_time();
rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags);
t = vfslog_time() - t;
vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0);
vfslog_string(pVfs, zName);
return rc;
}
static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
int rc;
sqlite3_uint64 t;
t = vfslog_time();
rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync);
t = vfslog_time() - t;
vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0);
vfslog_string(pVfs, zPath);
return rc;
}
static int vfslogAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
int rc;
sqlite3_uint64 t;
t = vfslog_time();
rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut);
t = vfslog_time() - t;
vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut);
vfslog_string(pVfs, zPath);
return rc;
}
static int vfslogFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
}
static void *vfslogDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
}
static void vfslogDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
}
static void (*vfslogDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym);
}
static void vfslogDlClose(sqlite3_vfs *pVfs, void *pHandle){
REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
}
static int vfslogRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
}
static int vfslogSleep(sqlite3_vfs *pVfs, int nMicro){
return REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro);
}
static int vfslogCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut);
}
static int vfslogGetLastError(sqlite3_vfs *pVfs, int a, char *b){
return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), a, b);
}
static int vfslogCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), p);
}
static void vfslog_flush(VfslogVfs *p){
#ifdef SQLITE_TEST
extern int sqlite3_io_error_pending;
extern int sqlite3_io_error_persist;
extern int sqlite3_diskfull_pending;
int pending = sqlite3_io_error_pending;
int persist = sqlite3_io_error_persist;
int diskfull = sqlite3_diskfull_pending;
sqlite3_io_error_pending = 0;
sqlite3_io_error_persist = 0;
sqlite3_diskfull_pending = 0;
#endif
if( p->nBuf ){
p->pLog->pMethods->xWrite(p->pLog, p->aBuf, p->nBuf, p->iOffset);
p->iOffset += p->nBuf;
p->nBuf = 0;
}
#ifdef SQLITE_TEST
sqlite3_io_error_pending = pending;
sqlite3_io_error_persist = persist;
sqlite3_diskfull_pending = diskfull;
#endif
}
static void put32bits(unsigned char *p, unsigned int v){
p[0] = v>>24;
p[1] = (unsigned char)(v>>16);
p[2] = (unsigned char)(v>>8);
p[3] = (unsigned char)v;
}
static void vfslog_call(
sqlite3_vfs *pVfs,
int eEvent,
int iFileid,
sqlite3_int64 nClick,
int return_code,
int size,
int offset
){
VfslogVfs *p = (VfslogVfs *)pVfs;
unsigned char *zRec;
if( (24+p->nBuf)>sizeof(p->aBuf) ){
vfslog_flush(p);
}
zRec = (unsigned char *)&p->aBuf[p->nBuf];
put32bits(&zRec[0], eEvent);
put32bits(&zRec[4], iFileid);
put32bits(&zRec[8], (unsigned int)(nClick&0xffff));
put32bits(&zRec[12], return_code);
put32bits(&zRec[16], size);
put32bits(&zRec[20], offset);
p->nBuf += 24;
}
static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){
VfslogVfs *p = (VfslogVfs *)pVfs;
unsigned char *zRec;
int nStr = zStr ? (int)strlen(zStr) : 0;
if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){
vfslog_flush(p);
}
zRec = (unsigned char *)&p->aBuf[p->nBuf];
put32bits(&zRec[0], nStr);
if( zStr ){
memcpy(&zRec[4], zStr, nStr);
}
p->nBuf += (4 + nStr);
}
static void vfslog_finalize(VfslogVfs *p){
if( p->pLog->pMethods ){
vfslog_flush(p);
p->pLog->pMethods->xClose(p->pLog);
}
sqlite3_free(p);
}
int sqlite3_vfslog_finalize(const char *zVfs){
sqlite3_vfs *pVfs;
pVfs = sqlite3_vfs_find(zVfs);
if( !pVfs || pVfs->xOpen!=vfslogOpen ){
return SQLITE_ERROR;
}
sqlite3_vfs_unregister(pVfs);
vfslog_finalize((VfslogVfs *)pVfs);
return SQLITE_OK;
}
int sqlite3_vfslog_new(
const char *zVfs,
const char *zParentVfs,
const char *zLog
){
VfslogVfs *p;
sqlite3_vfs *pParent;
int nByte;
int flags;
int rc;
char *zFile;
int nVfs;
pParent = sqlite3_vfs_find(zParentVfs);
if( !pParent ){
return SQLITE_ERROR;
}
nVfs = (int)strlen(zVfs);
nByte = sizeof(VfslogVfs) + pParent->szOsFile + nVfs+1+pParent->mxPathname+1;
p = (VfslogVfs *)sqlite3_malloc(nByte);
memset(p, 0, nByte);
p->pVfs = pParent;
p->pLog = (sqlite3_file *)&p[1];
memcpy(&p->base, &vfslog_vfs, sizeof(sqlite3_vfs));
p->base.zName = &((char *)p->pLog)[pParent->szOsFile];
p->base.szOsFile += pParent->szOsFile;
memcpy((char *)p->base.zName, zVfs, nVfs);
zFile = (char *)&p->base.zName[nVfs+1];
pParent->xFullPathname(pParent, zLog, pParent->mxPathname, zFile);
flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SUPER_JOURNAL;
pParent->xDelete(pParent, zFile, 0);
rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags);
if( rc==SQLITE_OK ){
memcpy(p->aBuf, "sqlite_ostrace1.....", 20);
p->iOffset = 0;
p->nBuf = 20;
rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1);
}
if( rc ){
vfslog_finalize(p);
}
return rc;
}
int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){
sqlite3_vfs *pVfs;
pVfs = sqlite3_vfs_find(zVfs);
if( !pVfs || pVfs->xOpen!=vfslogOpen ){
return SQLITE_ERROR;
}
vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0);
vfslog_string(pVfs, zMsg);
return SQLITE_OK;
}
static const char *vfslog_eventname(int eEvent){
const char *zEvent = 0;
switch( eEvent ){
case OS_CLOSE: zEvent = "xClose"; break;
case OS_READ: zEvent = "xRead"; break;
case OS_WRITE: zEvent = "xWrite"; break;
case OS_TRUNCATE: zEvent = "xTruncate"; break;
case OS_SYNC: zEvent = "xSync"; break;
case OS_FILESIZE: zEvent = "xFilesize"; break;
case OS_LOCK: zEvent = "xLock"; break;
case OS_UNLOCK: zEvent = "xUnlock"; break;
case OS_CHECKRESERVEDLOCK: zEvent = "xCheckResLock"; break;
case OS_FILECONTROL: zEvent = "xFileControl"; break;
case OS_SECTORSIZE: zEvent = "xSectorSize"; break;
case OS_DEVCHAR: zEvent = "xDeviceChar"; break;
case OS_OPEN: zEvent = "xOpen"; break;
case OS_DELETE: zEvent = "xDelete"; break;
case OS_ACCESS: zEvent = "xAccess"; break;
case OS_FULLPATHNAME: zEvent = "xFullPathname"; break;
case OS_RANDOMNESS: zEvent = "xRandomness"; break;
case OS_SLEEP: zEvent = "xSleep"; break;
case OS_CURRENTTIME: zEvent = "xCurrentTime"; break;
case OS_SHMUNMAP: zEvent = "xShmUnmap"; break;
case OS_SHMLOCK: zEvent = "xShmLock"; break;
case OS_SHMBARRIER: zEvent = "xShmBarrier"; break;
case OS_SHMMAP: zEvent = "xShmMap"; break;
case OS_ANNOTATE: zEvent = "annotation"; break;
}
return zEvent;
}
typedef struct VfslogVtab VfslogVtab;
typedef struct VfslogCsr VfslogCsr;
struct VfslogVtab {
sqlite3_vtab base;
sqlite3_file *pFd;
sqlite3_int64 nByte;
char *zFile;
};
struct VfslogCsr {
sqlite3_vtab_cursor base;
sqlite3_int64 iRowid;
sqlite3_int64 iOffset;
char *zTransient;
int nFile;
char **azFile;
unsigned char aBuf[1024];
};
static unsigned int get32bits(unsigned char *p){
return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
}
static void dequote(char *z){
char quote;
quote = z[0];
if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
int iIn = 1;
int iOut = 0;
if( quote=='[' ) quote = ']';
while( z[iIn] ){
if( z[iIn]==quote ){
if( z[iIn+1]!=quote ) break;
z[iOut++] = quote;
iIn += 2;
}else{
z[iOut++] = z[iIn++];
}
}
z[iOut] = '\0';
}
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
static int vlogConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
sqlite3_vfs *pVfs;
int flags;
VfslogVtab *p;
int rc;
int nByte;
char *zFile;
*ppVtab = 0;
pVfs = sqlite3_vfs_find(0);
nByte = sizeof(VfslogVtab) + pVfs->szOsFile + pVfs->mxPathname;
p = sqlite3_malloc(nByte);
if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, nByte);
p->pFd = (sqlite3_file *)&p[1];
p->zFile = &((char *)p->pFd)[pVfs->szOsFile];
zFile = sqlite3_mprintf("%s", argv[3]);
if( !zFile ){
sqlite3_free(p);
return SQLITE_NOMEM;
}
dequote(zFile);
pVfs->xFullPathname(pVfs, zFile, pVfs->mxPathname, p->zFile);
sqlite3_free(zFile);
flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_SUPER_JOURNAL;
rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags);
if( rc==SQLITE_OK ){
p->pFd->pMethods->xFileSize(p->pFd, &p->nByte);
sqlite3_declare_vtab(db,
"CREATE TABLE xxx(event, file, click, rc, size, offset)"
);
*ppVtab = &p->base;
}else{
sqlite3_free(p);
}
return rc;
}
static int vlogBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
pIdxInfo->estimatedCost = 10.0;
return SQLITE_OK;
}
static int vlogDisconnect(sqlite3_vtab *pVtab){
VfslogVtab *p = (VfslogVtab *)pVtab;
if( p->pFd->pMethods ){
p->pFd->pMethods->xClose(p->pFd);
p->pFd->pMethods = 0;
}
sqlite3_free(p);
return SQLITE_OK;
}
static int vlogOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
VfslogCsr *pCsr;
pCsr = sqlite3_malloc(sizeof(VfslogCsr));
if( !pCsr ) return SQLITE_NOMEM;
memset(pCsr, 0, sizeof(VfslogCsr));
*ppCursor = &pCsr->base;
return SQLITE_OK;
}
static int vlogClose(sqlite3_vtab_cursor *pCursor){
VfslogCsr *p = (VfslogCsr *)pCursor;
int i;
for(i=0; i<p->nFile; i++){
sqlite3_free(p->azFile[i]);
}
sqlite3_free(p->azFile);
sqlite3_free(p->zTransient);
sqlite3_free(p);
return SQLITE_OK;
}
static int vlogNext(sqlite3_vtab_cursor *pCursor){
VfslogCsr *pCsr = (VfslogCsr *)pCursor;
VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
int rc = SQLITE_OK;
int nRead;
sqlite3_free(pCsr->zTransient);
pCsr->zTransient = 0;
nRead = 24;
if( pCsr->iOffset+nRead<=p->nByte ){
int eEvent;
rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset);
eEvent = get32bits(pCsr->aBuf);
if( (rc==SQLITE_OK)
&& (eEvent==OS_OPEN || eEvent==OS_DELETE || eEvent==OS_ACCESS)
){
char buf[4];
rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead);
nRead += 4;
if( rc==SQLITE_OK ){
int nStr = get32bits((unsigned char *)buf);
char *zStr = sqlite3_malloc(nStr+1);
rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead);
zStr[nStr] = '\0';
nRead += nStr;
if( eEvent==OS_OPEN ){
int iFileid = get32bits(&pCsr->aBuf[4]);
if( iFileid>=pCsr->nFile ){
int nNew = sizeof(pCsr->azFile[0])*(iFileid+1);
pCsr->azFile = (char **)sqlite3_realloc(pCsr->azFile, nNew);
nNew -= sizeof(pCsr->azFile[0])*pCsr->nFile;
memset(&pCsr->azFile[pCsr->nFile], 0, nNew);
pCsr->nFile = iFileid+1;
}
sqlite3_free(pCsr->azFile[iFileid]);
pCsr->azFile[iFileid] = zStr;
}else{
pCsr->zTransient = zStr;
}
}
}
}
pCsr->iRowid += 1;
pCsr->iOffset += nRead;
return rc;
}
static int vlogEof(sqlite3_vtab_cursor *pCursor){
VfslogCsr *pCsr = (VfslogCsr *)pCursor;
VfslogVtab *p = (VfslogVtab *)pCursor->pVtab;
return (pCsr->iOffset>=p->nByte);
}
static int vlogFilter(
sqlite3_vtab_cursor *pCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
VfslogCsr *pCsr = (VfslogCsr *)pCursor;
pCsr->iRowid = 0;
pCsr->iOffset = 20;
return vlogNext(pCursor);
}
static int vlogColumn(
sqlite3_vtab_cursor *pCursor,
sqlite3_context *ctx,
int i
){
unsigned int val;
VfslogCsr *pCsr = (VfslogCsr *)pCursor;
assert( i<7 );
val = get32bits(&pCsr->aBuf[4*i]);
switch( i ){
case 0: {
sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC);
break;
}
case 1: {
char *zStr = pCsr->zTransient;
if( val!=0 && val<(unsigned)pCsr->nFile ){
zStr = pCsr->azFile[val];
}
sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT);
break;
}
default:
sqlite3_result_int(ctx, val);
break;
}
return SQLITE_OK;
}
static int vlogRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
VfslogCsr *pCsr = (VfslogCsr *)pCursor;
*pRowid = pCsr->iRowid;
return SQLITE_OK;
}
int sqlite3_vfslog_register(sqlite3 *db){
static sqlite3_module vfslog_module = {
0,
vlogConnect,
vlogConnect,
vlogBestIndex,
vlogDisconnect,
vlogDisconnect,
vlogOpen,
vlogClose,
vlogFilter,
vlogNext,
vlogEof,
vlogColumn,
vlogRowid,
0,
0,
0,
0,
0,
0,
0,
};
sqlite3_create_module(db, "vfslog", &vfslog_module, 0);
return SQLITE_OK;
}
#endif
#if defined(SQLITE_TEST) || defined(TCLSH)
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
static int SQLITE_TCLAPI test_vfslog(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
struct SqliteDb { sqlite3 *db; };
sqlite3 *db;
Tcl_CmdInfo cmdInfo;
int rc = SQLITE_ERROR;
static const char *strs[] = { "annotate", "finalize", "new", "register", 0 };
enum VL_enum { VL_ANNOTATE, VL_FINALIZE, VL_NEW, VL_REGISTER };
int iSub;
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
return TCL_ERROR;
}
if( Tcl_GetIndexFromObj(interp, objv[1], strs, "sub-command", 0, &iSub) ){
return TCL_ERROR;
}
switch( (enum VL_enum)iSub ){
case VL_ANNOTATE: {
char *zVfs;
char *zMsg;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 3, objv, "VFS");
return TCL_ERROR;
}
zVfs = Tcl_GetString(objv[2]);
zMsg = Tcl_GetString(objv[3]);
rc = sqlite3_vfslog_annotate(zVfs, zMsg);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "failed", 0);
return TCL_ERROR;
}
break;
}
case VL_FINALIZE: {
char *zVfs;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "VFS");
return TCL_ERROR;
}
zVfs = Tcl_GetString(objv[2]);
rc = sqlite3_vfslog_finalize(zVfs);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "failed", 0);
return TCL_ERROR;
}
break;
};
case VL_NEW: {
char *zVfs;
char *zParent;
char *zLog;
if( objc!=5 ){
Tcl_WrongNumArgs(interp, 2, objv, "VFS PARENT LOGFILE");
return TCL_ERROR;
}
zVfs = Tcl_GetString(objv[2]);
zParent = Tcl_GetString(objv[3]);
zLog = Tcl_GetString(objv[4]);
if( *zParent=='\0' ) zParent = 0;
rc = sqlite3_vfslog_new(zVfs, zParent, zLog);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "failed", 0);
return TCL_ERROR;
}
break;
};
case VL_REGISTER: {
char *zDb;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "DB");
return TCL_ERROR;
}
#ifdef SQLITE_OMIT_VIRTUALTABLE
Tcl_AppendResult(interp, "vfslog not available because of "
"SQLITE_OMIT_VIRTUALTABLE", (void*)0);
return TCL_ERROR;
#else
zDb = Tcl_GetString(objv[2]);
if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
rc = sqlite3_vfslog_register(db);
}
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "bad sqlite3 handle: ", zDb, (void*)0);
return TCL_ERROR;
}
break;
#endif
}
}
return TCL_OK;
}
int SqlitetestOsinst_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "vfslog", test_vfslog, 0, 0);
return TCL_OK;
}
#endif