Annotation of embedaddon/sqlite3/src/test_osinst.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>