Annotation of embedaddon/sqlite3/src/test_osinst.c, revision 1.1.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>