modernc.org/cc@v1.0.1/v2/testdata/_sqlite/src/test_osinst.c (about)

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