persistentstorage/sqlite3api/TEST/SRC/test_osinst.c
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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 ** $Id: test_osinst.c,v 1.18 2008/07/25 13:32:45 drh Exp $
       
    18 */
       
    19 
       
    20 #ifdef SQLITE_ENABLE_INSTVFS
       
    21 /*
       
    22 ** C interface:
       
    23 **
       
    24 **   sqlite3_instvfs_create()
       
    25 **   sqlite3_instvfs_destroy()
       
    26 **   sqlite3_instvfs_configure()
       
    27 **
       
    28 **   sqlite3_instvfs_reset()
       
    29 **   sqlite3_instvfs_get()
       
    30 **
       
    31 **   sqlite3_instvfs_binarylog
       
    32 **   sqlite3_instvfs_binarylog_marker
       
    33 **
       
    34 ** Tcl interface (omitted if SQLITE_TEST is not set):
       
    35 ** 
       
    36 **   sqlite3_instvfs create NAME ?PARENT?
       
    37 **
       
    38 **       Create and register new vfs called $NAME, which is a wrapper around
       
    39 **       the existing vfs $PARENT. If the PARENT argument is omitted, the
       
    40 **       new vfs is a wrapper around the current default vfs.
       
    41 **
       
    42 **   sqlite3_instvfs destroy NAME
       
    43 **
       
    44 **       Deregister and destroy the vfs named $NAME, which must have been
       
    45 **       created by an earlier invocation of [sqlite3_instvfs create].
       
    46 **
       
    47 **   sqlite3_instvfs configure NAME SCRIPT
       
    48 **
       
    49 **       Configure the callback script for the vfs $NAME, which much have
       
    50 **       been created by an earlier invocation of [sqlite3_instvfs create].
       
    51 **       After a callback script has been configured, it is invoked each
       
    52 **       time a vfs or file method is called by SQLite. Before invoking
       
    53 **       the callback script, five arguments are appended to it:
       
    54 **
       
    55 **         * The name of the invoked method - i.e. "xRead".
       
    56 **
       
    57 **         * The time consumed by the method call as measured by 
       
    58 **           sqlite3Hwtime() (an integer value)
       
    59 **
       
    60 **         * A string value with a different meaning for different calls. 
       
    61 **           For file methods, the name of the file being operated on. For
       
    62 **           other methods it is the filename argument, if any.
       
    63 **
       
    64 **         * A 32-bit integer value with a call-specific meaning.
       
    65 **
       
    66 **         * A 64-bit integer value. For xRead() and xWrite() calls this
       
    67 **           is the file offset being written to or read from. Unused by
       
    68 **           all other calls.
       
    69 **
       
    70 **   sqlite3_instvfs reset NAME
       
    71 **
       
    72 **       Zero the internal event counters associated with vfs $NAME, 
       
    73 **       which must have been created by an earlier invocation of 
       
    74 **       [sqlite3_instvfs create].
       
    75 **
       
    76 **   sqlite3_instvfs report NAME
       
    77 **
       
    78 **       Return the values of the internal event counters associated 
       
    79 **       with vfs $NAME. The report format is a list with one element
       
    80 **       for each method call (xWrite, xRead etc.). Each element is
       
    81 **       itself a list with three elements:
       
    82 **
       
    83 **         * The name of the method call - i.e. "xWrite",
       
    84 **         * The total number of calls to the method (an integer).
       
    85 **         * The aggregate time consumed by all calls to the method as
       
    86 **           measured by sqlite3Hwtime() (an integer).
       
    87 */
       
    88 
       
    89 #include "sqlite3.h"
       
    90 #include <string.h>
       
    91 #include <assert.h>
       
    92 
       
    93 /*
       
    94 ** Maximum pathname length supported by the inst backend.
       
    95 */
       
    96 #define INST_MAX_PATHNAME 512
       
    97 
       
    98 
       
    99 /* File methods */
       
   100 /* Vfs methods */
       
   101 #define OS_ACCESS            1
       
   102 #define OS_CHECKRESERVEDLOCK 2
       
   103 #define OS_CLOSE             3
       
   104 #define OS_CURRENTTIME       4
       
   105 #define OS_DELETE            5
       
   106 #define OS_DEVCHAR           6
       
   107 #define OS_FILECONTROL       7
       
   108 #define OS_FILESIZE          8
       
   109 #define OS_FULLPATHNAME      9
       
   110 #define OS_LOCK              11
       
   111 #define OS_OPEN              12
       
   112 #define OS_RANDOMNESS        13
       
   113 #define OS_READ              14 
       
   114 #define OS_SECTORSIZE        15
       
   115 #define OS_SLEEP             16
       
   116 #define OS_SYNC              17
       
   117 #define OS_TRUNCATE          18
       
   118 #define OS_UNLOCK            19
       
   119 #define OS_WRITE             20
       
   120 
       
   121 #define OS_NUMEVENTS         21
       
   122 
       
   123 #define BINARYLOG_STRING     30
       
   124 #define BINARYLOG_MARKER     31
       
   125 
       
   126 #define BINARYLOG_PREPARE_V2 64
       
   127 #define BINARYLOG_STEP       65
       
   128 #define BINARYLOG_FINALIZE   66
       
   129 
       
   130 struct InstVfs {
       
   131   sqlite3_vfs base;
       
   132   sqlite3_vfs *pVfs;
       
   133 
       
   134   void *pClient;
       
   135   void (*xDel)(void *);
       
   136   void (*xCall)(void *, int, int, sqlite3_int64, int, const char *, int, int, sqlite3_int64);
       
   137 
       
   138   /* Counters */
       
   139   sqlite3_int64 aTime[OS_NUMEVENTS];
       
   140   int aCount[OS_NUMEVENTS];
       
   141 
       
   142   int iNextFileId;
       
   143 };
       
   144 typedef struct InstVfs InstVfs;
       
   145 
       
   146 #define REALVFS(p) (((InstVfs *)(p))->pVfs)
       
   147 
       
   148 typedef struct inst_file inst_file;
       
   149 struct inst_file {
       
   150   sqlite3_file base;
       
   151   sqlite3_file *pReal;
       
   152   InstVfs *pInstVfs;
       
   153   const char *zName;
       
   154   int iFileId;               /* File id number */
       
   155   int flags;
       
   156 };
       
   157 
       
   158 /*
       
   159 ** Method declarations for inst_file.
       
   160 */
       
   161 static int instClose(sqlite3_file*);
       
   162 static int instRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
       
   163 static int instWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
       
   164 static int instTruncate(sqlite3_file*, sqlite3_int64 size);
       
   165 static int instSync(sqlite3_file*, int flags);
       
   166 static int instFileSize(sqlite3_file*, sqlite3_int64 *pSize);
       
   167 static int instLock(sqlite3_file*, int);
       
   168 static int instUnlock(sqlite3_file*, int);
       
   169 static int instCheckReservedLock(sqlite3_file*, int *pResOut);
       
   170 static int instFileControl(sqlite3_file*, int op, void *pArg);
       
   171 static int instSectorSize(sqlite3_file*);
       
   172 static int instDeviceCharacteristics(sqlite3_file*);
       
   173 
       
   174 /*
       
   175 ** Method declarations for inst_vfs.
       
   176 */
       
   177 static int instOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
       
   178 static int instDelete(sqlite3_vfs*, const char *zName, int syncDir);
       
   179 static int instAccess(sqlite3_vfs*, const char *zName, int flags, int *);
       
   180 static int instFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
       
   181 static void *instDlOpen(sqlite3_vfs*, const char *zFilename);
       
   182 static void instDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
       
   183 static void *instDlSym(sqlite3_vfs*,void*, const char *zSymbol);
       
   184 static void instDlClose(sqlite3_vfs*, void*);
       
   185 static int instRandomness(sqlite3_vfs*, int nByte, char *zOut);
       
   186 static int instSleep(sqlite3_vfs*, int microseconds);
       
   187 static int instCurrentTime(sqlite3_vfs*, double*);
       
   188 
       
   189 static void binarylog_blob(sqlite3_vfs *, const char *, int, int); 
       
   190 
       
   191 static sqlite3_vfs inst_vfs = {
       
   192   1,                      /* iVersion */
       
   193   sizeof(inst_file),      /* szOsFile */
       
   194   INST_MAX_PATHNAME,      /* mxPathname */
       
   195   0,                      /* pNext */
       
   196   0,                      /* zName */
       
   197   0,                      /* pAppData */
       
   198   instOpen,               /* xOpen */
       
   199   instDelete,             /* xDelete */
       
   200   instAccess,             /* xAccess */
       
   201   instFullPathname,       /* xFullPathname */
       
   202   instDlOpen,             /* xDlOpen */
       
   203   instDlError,            /* xDlError */
       
   204   instDlSym,              /* xDlSym */
       
   205   instDlClose,            /* xDlClose */
       
   206   instRandomness,         /* xRandomness */
       
   207   instSleep,              /* xSleep */
       
   208   instCurrentTime         /* xCurrentTime */
       
   209 };
       
   210 
       
   211 static sqlite3_io_methods inst_io_methods = {
       
   212   1,                            /* iVersion */
       
   213   instClose,                      /* xClose */
       
   214   instRead,                       /* xRead */
       
   215   instWrite,                      /* xWrite */
       
   216   instTruncate,                   /* xTruncate */
       
   217   instSync,                       /* xSync */
       
   218   instFileSize,                   /* xFileSize */
       
   219   instLock,                       /* xLock */
       
   220   instUnlock,                     /* xUnlock */
       
   221   instCheckReservedLock,          /* xCheckReservedLock */
       
   222   instFileControl,                /* xFileControl */
       
   223   instSectorSize,                 /* xSectorSize */
       
   224   instDeviceCharacteristics       /* xDeviceCharacteristics */
       
   225 };
       
   226 
       
   227 /* 
       
   228 ** hwtime.h contains inline assembler code for implementing 
       
   229 ** high-performance timing routines.
       
   230 */
       
   231 #include "hwtime.h"
       
   232 
       
   233 #define OS_TIME_IO(eEvent, A, B, Call) {     \
       
   234   inst_file *p = (inst_file *)pFile;         \
       
   235   InstVfs *pInstVfs = p->pInstVfs;           \
       
   236   int rc;                                    \
       
   237   sqlite_uint64 t = sqlite3Hwtime();         \
       
   238   rc = Call;                                 \
       
   239   t = sqlite3Hwtime() - t;                   \
       
   240   pInstVfs->aTime[eEvent] += t;              \
       
   241   pInstVfs->aCount[eEvent] += 1;             \
       
   242   if( pInstVfs->xCall ){                     \
       
   243     pInstVfs->xCall(                         \
       
   244       pInstVfs->pClient,eEvent,p->iFileId,t,rc,p->zName,p->flags,A,B  \
       
   245     );                                       \
       
   246   }                                          \
       
   247   return rc;                                 \
       
   248 }
       
   249 
       
   250 #define OS_TIME_VFS(eEvent, Z, flags, A, B, Call) {      \
       
   251   InstVfs *pInstVfs = (InstVfs *)pVfs;   \
       
   252   int rc;                                \
       
   253   sqlite_uint64 t = sqlite3Hwtime();     \
       
   254   rc = Call;                             \
       
   255   t = sqlite3Hwtime() - t;               \
       
   256   pInstVfs->aTime[eEvent] += t;          \
       
   257   pInstVfs->aCount[eEvent] += 1;         \
       
   258   if( pInstVfs->xCall ){                 \
       
   259     pInstVfs->xCall(pInstVfs->pClient,eEvent,0, t, rc, Z, flags, A, B); \
       
   260   }                                      \
       
   261   return rc;                             \
       
   262 }
       
   263 
       
   264 /*
       
   265 ** Close an inst-file.
       
   266 */
       
   267 static int instClose(sqlite3_file *pFile){
       
   268   OS_TIME_IO(OS_CLOSE, 0, 0, 
       
   269     (p->pReal->pMethods ? p->pReal->pMethods->xClose(p->pReal) : SQLITE_OK)
       
   270   );
       
   271 }
       
   272 
       
   273 /*
       
   274 ** Read data from an inst-file.
       
   275 */
       
   276 static int instRead(
       
   277   sqlite3_file *pFile, 
       
   278   void *zBuf, 
       
   279   int iAmt, 
       
   280   sqlite_int64 iOfst
       
   281 ){
       
   282   sqlite3_vfs *pVfs = (sqlite3_vfs *)(((inst_file *)pFile)->pInstVfs);
       
   283   OS_TIME_IO(OS_READ, iAmt, (binarylog_blob(pVfs, zBuf, iAmt, 1), iOfst), 
       
   284       p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst)
       
   285   );
       
   286 }
       
   287 
       
   288 /*
       
   289 ** Write data to an inst-file.
       
   290 */
       
   291 static int instWrite(
       
   292   sqlite3_file *pFile,
       
   293   const void *z,
       
   294   int iAmt,
       
   295   sqlite_int64 iOfst
       
   296 ){
       
   297   sqlite3_vfs *pVfs = (sqlite3_vfs *)(((inst_file *)pFile)->pInstVfs);
       
   298   binarylog_blob(pVfs, z, iAmt, 1);
       
   299   OS_TIME_IO(OS_WRITE, iAmt, iOfst, 
       
   300       p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst)
       
   301   );
       
   302 }
       
   303 
       
   304 /*
       
   305 ** Truncate an inst-file.
       
   306 */
       
   307 static int instTruncate(sqlite3_file *pFile, sqlite_int64 size){
       
   308   OS_TIME_IO(OS_TRUNCATE, 0, (int)size, 
       
   309     p->pReal->pMethods->xTruncate(p->pReal, size)
       
   310   );
       
   311 }
       
   312 
       
   313 /*
       
   314 ** Sync an inst-file.
       
   315 */
       
   316 static int instSync(sqlite3_file *pFile, int flags){
       
   317   OS_TIME_IO(OS_SYNC, flags, 0, p->pReal->pMethods->xSync(p->pReal, flags));
       
   318 }
       
   319 
       
   320 /*
       
   321 ** Return the current file-size of an inst-file.
       
   322 */
       
   323 static int instFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
       
   324   OS_TIME_IO(OS_FILESIZE, (int)(*pSize), 0, 
       
   325     p->pReal->pMethods->xFileSize(p->pReal, pSize)
       
   326   );
       
   327 }
       
   328 
       
   329 /*
       
   330 ** Lock an inst-file.
       
   331 */
       
   332 static int instLock(sqlite3_file *pFile, int eLock){
       
   333   OS_TIME_IO(OS_LOCK, eLock, 0, p->pReal->pMethods->xLock(p->pReal, eLock));
       
   334 }
       
   335 
       
   336 /*
       
   337 ** Unlock an inst-file.
       
   338 */
       
   339 static int instUnlock(sqlite3_file *pFile, int eLock){
       
   340   OS_TIME_IO(OS_UNLOCK, eLock, 0, p->pReal->pMethods->xUnlock(p->pReal, eLock));
       
   341 }
       
   342 
       
   343 /*
       
   344 ** Check if another file-handle holds a RESERVED lock on an inst-file.
       
   345 */
       
   346 static int instCheckReservedLock(sqlite3_file *pFile, int *pResOut){
       
   347   OS_TIME_IO(OS_CHECKRESERVEDLOCK, 0, 0, 
       
   348       p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut)
       
   349   );
       
   350 }
       
   351 
       
   352 /*
       
   353 ** File control method. For custom operations on an inst-file.
       
   354 */
       
   355 static int instFileControl(sqlite3_file *pFile, int op, void *pArg){
       
   356   OS_TIME_IO(OS_FILECONTROL, 0, 0, p->pReal->pMethods->xFileControl(p->pReal, op, pArg));
       
   357 }
       
   358 
       
   359 /*
       
   360 ** Return the sector-size in bytes for an inst-file.
       
   361 */
       
   362 static int instSectorSize(sqlite3_file *pFile){
       
   363   OS_TIME_IO(OS_SECTORSIZE, 0, 0, p->pReal->pMethods->xSectorSize(p->pReal));
       
   364 }
       
   365 
       
   366 /*
       
   367 ** Return the device characteristic flags supported by an inst-file.
       
   368 */
       
   369 static int instDeviceCharacteristics(sqlite3_file *pFile){
       
   370   OS_TIME_IO(OS_DEVCHAR, 0, 0, p->pReal->pMethods->xDeviceCharacteristics(p->pReal));
       
   371 }
       
   372 
       
   373 /*
       
   374 ** Open an inst file handle.
       
   375 */
       
   376 static int instOpen(
       
   377   sqlite3_vfs *pVfs,
       
   378   const char *zName,
       
   379   sqlite3_file *pFile,
       
   380   int flags,
       
   381   int *pOutFlags
       
   382 ){
       
   383   inst_file *p = (inst_file *)pFile;
       
   384   pFile->pMethods = &inst_io_methods;
       
   385   p->pReal = (sqlite3_file *)&p[1];
       
   386   p->pInstVfs = (InstVfs *)pVfs;
       
   387   p->zName = zName;
       
   388   p->flags = flags;
       
   389   p->iFileId = ++p->pInstVfs->iNextFileId;
       
   390 
       
   391   binarylog_blob(pVfs, zName, -1, 0);
       
   392   OS_TIME_VFS(OS_OPEN, zName, flags, p->iFileId, 0,
       
   393     REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags)
       
   394   );
       
   395 }
       
   396 
       
   397 /*
       
   398 ** Delete the file located at zPath. If the dirSync argument is true,
       
   399 ** ensure the file-system modifications are synced to disk before
       
   400 ** returning.
       
   401 */
       
   402 static int instDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
       
   403   binarylog_blob(pVfs, zPath, -1, 0);
       
   404   OS_TIME_VFS(OS_DELETE, zPath, 0, dirSync, 0,
       
   405     REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync) 
       
   406   );
       
   407 }
       
   408 
       
   409 /*
       
   410 ** Test for access permissions. Return true if the requested permission
       
   411 ** is available, or false otherwise.
       
   412 */
       
   413 static int instAccess(
       
   414   sqlite3_vfs *pVfs, 
       
   415   const char *zPath, 
       
   416   int flags, 
       
   417   int *pResOut
       
   418 ){
       
   419   binarylog_blob(pVfs, zPath, -1, 0);
       
   420   OS_TIME_VFS(OS_ACCESS, zPath, 0, flags, *pResOut, 
       
   421     REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut) 
       
   422   );
       
   423 }
       
   424 
       
   425 /*
       
   426 ** Populate buffer zOut with the full canonical pathname corresponding
       
   427 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
       
   428 ** of at least (INST_MAX_PATHNAME+1) bytes.
       
   429 */
       
   430 static int instFullPathname(
       
   431   sqlite3_vfs *pVfs, 
       
   432   const char *zPath, 
       
   433   int nOut, 
       
   434   char *zOut
       
   435 ){
       
   436   OS_TIME_VFS( OS_FULLPATHNAME, zPath, 0, 0, 0,
       
   437     REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
       
   438   );
       
   439 }
       
   440 
       
   441 /*
       
   442 ** Open the dynamic library located at zPath and return a handle.
       
   443 */
       
   444 static void *instDlOpen(sqlite3_vfs *pVfs, const char *zPath){
       
   445   return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
       
   446 }
       
   447 
       
   448 /*
       
   449 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
       
   450 ** utf-8 string describing the most recent error encountered associated 
       
   451 ** with dynamic libraries.
       
   452 */
       
   453 static void instDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
       
   454   REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
       
   455 }
       
   456 
       
   457 /*
       
   458 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
       
   459 */
       
   460 static void *instDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
       
   461   return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), pHandle, zSymbol);
       
   462 }
       
   463 
       
   464 /*
       
   465 ** Close the dynamic library handle pHandle.
       
   466 */
       
   467 static void instDlClose(sqlite3_vfs *pVfs, void *pHandle){
       
   468   REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
       
   469 }
       
   470 
       
   471 /*
       
   472 ** Populate the buffer pointed to by zBufOut with nByte bytes of 
       
   473 ** random data.
       
   474 */
       
   475 static int instRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
       
   476   OS_TIME_VFS( OS_RANDOMNESS, 0, 0, nByte, 0,
       
   477     REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
       
   478   );
       
   479 }
       
   480 
       
   481 /*
       
   482 ** Sleep for nMicro microseconds. Return the number of microseconds 
       
   483 ** actually slept.
       
   484 */
       
   485 static int instSleep(sqlite3_vfs *pVfs, int nMicro){
       
   486   OS_TIME_VFS( OS_SLEEP, 0, 0, nMicro, 0, 
       
   487     REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro) 
       
   488   );
       
   489 }
       
   490 
       
   491 /*
       
   492 ** Return the current time as a Julian Day number in *pTimeOut.
       
   493 */
       
   494 static int instCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
       
   495   OS_TIME_VFS( OS_CURRENTTIME, 0, 0, 0, 0,
       
   496     REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut) 
       
   497   );
       
   498 }
       
   499 
       
   500 sqlite3_vfs *sqlite3_instvfs_create(const char *zName, const char *zParent){
       
   501   int nByte;
       
   502   InstVfs *p;
       
   503   sqlite3_vfs *pParent;
       
   504 
       
   505   pParent = sqlite3_vfs_find(zParent);
       
   506   if( !pParent ){
       
   507     return 0;
       
   508   }
       
   509 
       
   510   nByte = strlen(zName) + 1 + sizeof(InstVfs);
       
   511   p = (InstVfs *)sqlite3_malloc(nByte);
       
   512   if( p ){
       
   513     char *zCopy = (char *)&p[1];
       
   514     memset(p, 0, nByte);
       
   515     memcpy(p, &inst_vfs, sizeof(sqlite3_vfs));
       
   516     p->pVfs = pParent;
       
   517     memcpy(zCopy, zName, strlen(zName));
       
   518     p->base.zName = (const char *)zCopy;
       
   519     p->base.szOsFile += pParent->szOsFile;
       
   520     sqlite3_vfs_register((sqlite3_vfs *)p, 0);
       
   521   }
       
   522 
       
   523   return (sqlite3_vfs *)p;
       
   524 }
       
   525 
       
   526 void sqlite3_instvfs_configure(
       
   527   sqlite3_vfs *pVfs,
       
   528   void (*xCall)(
       
   529       void*, 
       
   530       int,                           /* File id */
       
   531       int,                           /* Event code */
       
   532       sqlite3_int64, 
       
   533       int,                           /* Return code */
       
   534       const char*,                   /* File name */
       
   535       int, 
       
   536       int, 
       
   537       sqlite3_int64
       
   538   ),
       
   539   void *pClient,
       
   540   void (*xDel)(void *)
       
   541 ){
       
   542   InstVfs *p = (InstVfs *)pVfs;
       
   543   assert( pVfs->xOpen==instOpen );
       
   544   if( p->xDel ){
       
   545     p->xDel(p->pClient);
       
   546   }
       
   547   p->xCall = xCall;
       
   548   p->xDel = xDel;
       
   549   p->pClient = pClient;
       
   550 }
       
   551 
       
   552 void sqlite3_instvfs_destroy(sqlite3_vfs *pVfs){
       
   553   if( pVfs ){
       
   554     sqlite3_vfs_unregister(pVfs);
       
   555     sqlite3_instvfs_configure(pVfs, 0, 0, 0);
       
   556     sqlite3_free(pVfs);
       
   557   }
       
   558 }
       
   559 
       
   560 void sqlite3_instvfs_reset(sqlite3_vfs *pVfs){
       
   561   InstVfs *p = (InstVfs *)pVfs;
       
   562   assert( pVfs->xOpen==instOpen );
       
   563   memset(p->aTime, 0, sizeof(sqlite3_int64)*OS_NUMEVENTS);
       
   564   memset(p->aCount, 0, sizeof(int)*OS_NUMEVENTS);
       
   565 }
       
   566 
       
   567 const char *sqlite3_instvfs_name(int eEvent){
       
   568   const char *zEvent = 0;
       
   569 
       
   570   switch( eEvent ){
       
   571     case OS_CLOSE:             zEvent = "xClose"; break;
       
   572     case OS_READ:              zEvent = "xRead"; break;
       
   573     case OS_WRITE:             zEvent = "xWrite"; break;
       
   574     case OS_TRUNCATE:          zEvent = "xTruncate"; break;
       
   575     case OS_SYNC:              zEvent = "xSync"; break;
       
   576     case OS_FILESIZE:          zEvent = "xFilesize"; break;
       
   577     case OS_LOCK:              zEvent = "xLock"; break;
       
   578     case OS_UNLOCK:            zEvent = "xUnlock"; break;
       
   579     case OS_CHECKRESERVEDLOCK: zEvent = "xCheckReservedLock"; break;
       
   580     case OS_FILECONTROL:       zEvent = "xFileControl"; break;
       
   581     case OS_SECTORSIZE:        zEvent = "xSectorSize"; break;
       
   582     case OS_DEVCHAR:           zEvent = "xDeviceCharacteristics"; break;
       
   583     case OS_OPEN:              zEvent = "xOpen"; break;
       
   584     case OS_DELETE:            zEvent = "xDelete"; break;
       
   585     case OS_ACCESS:            zEvent = "xAccess"; break;
       
   586     case OS_FULLPATHNAME:      zEvent = "xFullPathname"; break;
       
   587     case OS_RANDOMNESS:        zEvent = "xRandomness"; break;
       
   588     case OS_SLEEP:             zEvent = "xSleep"; break;
       
   589     case OS_CURRENTTIME:       zEvent = "xCurrentTime"; break;
       
   590   }
       
   591 
       
   592   return zEvent;
       
   593 }
       
   594 
       
   595 void sqlite3_instvfs_get(
       
   596   sqlite3_vfs *pVfs, 
       
   597   int eEvent, 
       
   598   const char **pzEvent, 
       
   599   sqlite3_int64 *pnClick, 
       
   600   int *pnCall
       
   601 ){
       
   602   InstVfs *p = (InstVfs *)pVfs;
       
   603   assert( pVfs->xOpen==instOpen );
       
   604   if( eEvent<1 || eEvent>=OS_NUMEVENTS ){
       
   605     *pzEvent = 0;
       
   606     *pnClick = 0;
       
   607     *pnCall = 0;
       
   608     return;
       
   609   }
       
   610 
       
   611   *pzEvent = sqlite3_instvfs_name(eEvent);
       
   612   *pnClick = p->aTime[eEvent];
       
   613   *pnCall = p->aCount[eEvent];
       
   614 }
       
   615 
       
   616 #define BINARYLOG_BUFFERSIZE 8192
       
   617 
       
   618 struct InstVfsBinaryLog {
       
   619   int nBuf;
       
   620   char *zBuf;
       
   621   sqlite3_int64 iOffset;
       
   622   int log_data;
       
   623   sqlite3_file *pOut;
       
   624   char *zOut;                       /* Log file name */
       
   625 };
       
   626 typedef struct InstVfsBinaryLog InstVfsBinaryLog;
       
   627 
       
   628 static void put32bits(unsigned char *p, unsigned int v){
       
   629   p[0] = v>>24;
       
   630   p[1] = v>>16;
       
   631   p[2] = v>>8;
       
   632   p[3] = v;
       
   633 }
       
   634 
       
   635 static void binarylog_flush(InstVfsBinaryLog *pLog){
       
   636   sqlite3_file *pFile = pLog->pOut;
       
   637 
       
   638 #ifdef SQLITE_TEST
       
   639   extern int sqlite3_io_error_pending;
       
   640   extern int sqlite3_io_error_persist;
       
   641   extern int sqlite3_diskfull_pending;
       
   642 
       
   643   int pending = sqlite3_io_error_pending;
       
   644   int persist = sqlite3_io_error_persist;
       
   645   int diskfull = sqlite3_diskfull_pending;
       
   646 
       
   647   sqlite3_io_error_pending = 0;
       
   648   sqlite3_io_error_persist = 0;
       
   649   sqlite3_diskfull_pending = 0;
       
   650 #endif
       
   651 
       
   652   pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset);
       
   653   pLog->iOffset += pLog->nBuf;
       
   654   pLog->nBuf = 0;
       
   655 
       
   656 #ifdef SQLITE_TEST
       
   657   sqlite3_io_error_pending = pending;
       
   658   sqlite3_io_error_persist = persist;
       
   659   sqlite3_diskfull_pending = diskfull;
       
   660 #endif
       
   661 }
       
   662 
       
   663 static void binarylog_xcall(
       
   664   void *p,
       
   665   int eEvent,
       
   666   int iFileId,
       
   667   sqlite3_int64 nClick,
       
   668   int return_code,
       
   669   const char *zName,
       
   670   int flags,
       
   671   int nByte,
       
   672   sqlite3_int64 iOffset
       
   673 ){
       
   674   InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p;
       
   675   unsigned char *zRec;
       
   676   if( (28+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){
       
   677     binarylog_flush(pLog);
       
   678   }
       
   679   zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf];
       
   680   put32bits(&zRec[0], eEvent);
       
   681   put32bits(&zRec[4], (int)iFileId);
       
   682   put32bits(&zRec[8], (int)nClick);
       
   683   put32bits(&zRec[12], return_code);
       
   684   put32bits(&zRec[16], flags);
       
   685   put32bits(&zRec[20], nByte);
       
   686   put32bits(&zRec[24], (int)iOffset);
       
   687   pLog->nBuf += 28;
       
   688 }
       
   689 
       
   690 static void binarylog_xdel(void *p){
       
   691   /* Close the log file and free the memory allocated for the 
       
   692   ** InstVfsBinaryLog structure.
       
   693   */
       
   694   InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p;
       
   695   sqlite3_file *pFile = pLog->pOut;
       
   696   if( pLog->nBuf ){
       
   697     binarylog_flush(pLog);
       
   698   }
       
   699   pFile->pMethods->xClose(pFile);
       
   700   sqlite3_free(pLog->pOut);
       
   701   sqlite3_free(pLog->zBuf);
       
   702   sqlite3_free(pLog);
       
   703 }
       
   704 
       
   705 static void binarylog_blob(
       
   706   sqlite3_vfs *pVfs,
       
   707   const char *zBlob,
       
   708   int nBlob,
       
   709   int isBinary
       
   710 ){
       
   711   InstVfsBinaryLog *pLog;
       
   712   InstVfs *pInstVfs = (InstVfs *)pVfs;
       
   713 
       
   714   if( pVfs->xOpen!=instOpen || pInstVfs->xCall!=binarylog_xcall ){
       
   715     return;
       
   716   }
       
   717   pLog = (InstVfsBinaryLog *)pInstVfs->pClient;
       
   718   if( zBlob && (!isBinary || pLog->log_data) ){
       
   719     unsigned char *zRec;
       
   720     int nWrite;
       
   721 
       
   722     if( nBlob<0 ){
       
   723       nBlob = strlen(zBlob);
       
   724     }
       
   725     nWrite = nBlob + 28;
       
   726   
       
   727     if( (nWrite+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){
       
   728       binarylog_flush(pLog);
       
   729     }
       
   730   
       
   731     zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf];
       
   732     memset(zRec, 0, nWrite);
       
   733     put32bits(&zRec[0], BINARYLOG_STRING);
       
   734     put32bits(&zRec[4], (int)nBlob);
       
   735     put32bits(&zRec[8], (int)isBinary);
       
   736     memcpy(&zRec[28], zBlob, nBlob);
       
   737     pLog->nBuf += nWrite;
       
   738   }
       
   739 }
       
   740 
       
   741 void sqlite3_instvfs_binarylog_call(
       
   742   sqlite3_vfs *pVfs,
       
   743   int eEvent,
       
   744   sqlite3_int64 nClick,
       
   745   int return_code,
       
   746   const char *zString
       
   747 ){
       
   748   InstVfs *pInstVfs = (InstVfs *)pVfs;
       
   749   InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)pInstVfs->pClient;
       
   750 
       
   751   if( zString ){
       
   752     binarylog_blob(pVfs, zString, -1, 0);
       
   753   }
       
   754   binarylog_xcall(pLog, eEvent, 0, nClick, return_code, 0, 0, 0, 0);
       
   755 }
       
   756 
       
   757 void sqlite3_instvfs_binarylog_marker(
       
   758   sqlite3_vfs *pVfs,
       
   759   const char *zMarker
       
   760 ){
       
   761   InstVfs *pInstVfs = (InstVfs *)pVfs;
       
   762   InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)pInstVfs->pClient;
       
   763   binarylog_blob(pVfs, zMarker, -1, 0);
       
   764   binarylog_xcall(pLog, BINARYLOG_MARKER, 0, 0, 0, 0, 0, 0, 0);
       
   765 }
       
   766 
       
   767 sqlite3_vfs *sqlite3_instvfs_binarylog(
       
   768   const char *zVfs,
       
   769   const char *zParentVfs, 
       
   770   const char *zLog,
       
   771   int log_data
       
   772 ){
       
   773   InstVfsBinaryLog *p;
       
   774   sqlite3_vfs *pVfs;
       
   775   sqlite3_vfs *pParent;
       
   776   int nByte;
       
   777   int flags;
       
   778   int rc;
       
   779 
       
   780   pParent = sqlite3_vfs_find(zParentVfs);
       
   781   if( !pParent ){
       
   782     return 0;
       
   783   }
       
   784 
       
   785   nByte = sizeof(InstVfsBinaryLog) + pParent->mxPathname+1;
       
   786   p = (InstVfsBinaryLog *)sqlite3_malloc(nByte);
       
   787   memset(p, 0, nByte);
       
   788   p->zBuf = sqlite3_malloc(BINARYLOG_BUFFERSIZE);
       
   789   p->zOut = (char *)&p[1];
       
   790   p->pOut = (sqlite3_file *)sqlite3_malloc(pParent->szOsFile);
       
   791   p->log_data = log_data;
       
   792   pParent->xFullPathname(pParent, zLog, pParent->mxPathname, p->zOut);
       
   793   flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
       
   794   pParent->xDelete(pParent, p->zOut, 0);
       
   795   rc = pParent->xOpen(pParent, p->zOut, p->pOut, flags, &flags);
       
   796   if( rc==SQLITE_OK ){
       
   797     memcpy(p->zBuf, "sqlite_ostrace1.....", 20);
       
   798     p->iOffset = 0;
       
   799     p->nBuf = 20;
       
   800   }
       
   801   if( rc ){
       
   802     binarylog_xdel(p);
       
   803     return 0;
       
   804   }
       
   805 
       
   806   pVfs = sqlite3_instvfs_create(zVfs, zParentVfs);
       
   807   if( pVfs ){
       
   808     sqlite3_instvfs_configure(pVfs, binarylog_xcall, p, binarylog_xdel);
       
   809   }
       
   810 
       
   811   return pVfs;
       
   812 }
       
   813 #endif /* SQLITE_ENABLE_INSTVFS */
       
   814 
       
   815 /**************************************************************************
       
   816 ***************************************************************************
       
   817 ** Tcl interface starts here.
       
   818 */
       
   819 #if SQLITE_TEST
       
   820 
       
   821 #include "tcl.h"
       
   822 
       
   823 #ifdef SQLITE_ENABLE_INSTVFS
       
   824 struct InstVfsCall {
       
   825   Tcl_Interp *interp;
       
   826   Tcl_Obj *pScript;
       
   827 };
       
   828 typedef struct InstVfsCall InstVfsCall;
       
   829 
       
   830 static void test_instvfs_xcall(
       
   831   void *p,
       
   832   int eEvent,
       
   833   int iFileId,
       
   834   sqlite3_int64 nClick,
       
   835   int return_code,
       
   836   const char *zName,
       
   837   int flags,
       
   838   int nByte,
       
   839   sqlite3_int64 iOffset
       
   840 ){
       
   841   int rc;
       
   842   InstVfsCall *pCall = (InstVfsCall *)p;
       
   843   Tcl_Obj *pObj = Tcl_DuplicateObj( pCall->pScript);
       
   844   const char *zEvent = sqlite3_instvfs_name(eEvent);
       
   845 
       
   846   Tcl_IncrRefCount(pObj);
       
   847   Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zEvent, -1));
       
   848   Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(nClick));
       
   849   Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zName, -1));
       
   850   Tcl_ListObjAppendElement(0, pObj, Tcl_NewIntObj(nByte));
       
   851   Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(iOffset));
       
   852 
       
   853   rc = Tcl_EvalObjEx(pCall->interp, pObj, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
       
   854   if( rc ){
       
   855     Tcl_BackgroundError(pCall->interp);
       
   856   }
       
   857   Tcl_DecrRefCount(pObj);
       
   858 }
       
   859 
       
   860 static void test_instvfs_xdel(void *p){
       
   861   InstVfsCall *pCall = (InstVfsCall *)p;
       
   862   Tcl_DecrRefCount(pCall->pScript);
       
   863   sqlite3_free(pCall);
       
   864 }
       
   865 
       
   866 static int test_sqlite3_instvfs(
       
   867   void * clientData,
       
   868   Tcl_Interp *interp,
       
   869   int objc,
       
   870   Tcl_Obj *CONST objv[]
       
   871 ){
       
   872   static const char *IV_strs[] = 
       
   873                { "create",  "destroy",  "reset",  "report", "configure", "binarylog", "marker", 0 };
       
   874   enum IV_enum { IV_CREATE, IV_DESTROY, IV_RESET, IV_REPORT, IV_CONFIGURE, IV_BINARYLOG, IV_MARKER };
       
   875   int iSub;
       
   876 
       
   877   if( objc<2 ){
       
   878     Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
       
   879   }
       
   880   if( Tcl_GetIndexFromObj(interp, objv[1], IV_strs, "sub-command", 0, &iSub) ){
       
   881     return TCL_ERROR;
       
   882   }
       
   883 
       
   884   switch( (enum IV_enum)iSub ){
       
   885     case IV_CREATE: {
       
   886       char *zParent = 0;
       
   887       sqlite3_vfs *p;
       
   888       int isDefault = 0;
       
   889       if( objc>2 && 0==strcmp("-default", Tcl_GetString(objv[2])) ){
       
   890         isDefault = 1;
       
   891       }
       
   892       if( (objc-isDefault)!=4 && (objc-isDefault)!=3 ){
       
   893         Tcl_WrongNumArgs(interp, 2, objv, "?-default? NAME ?PARENT-VFS?");
       
   894         return TCL_ERROR;
       
   895       }
       
   896       if( objc==(4+isDefault) ){
       
   897         zParent = Tcl_GetString(objv[3+isDefault]);
       
   898       }
       
   899       p = sqlite3_instvfs_create(Tcl_GetString(objv[2+isDefault]), zParent);
       
   900       if( !p ){
       
   901         Tcl_AppendResult(interp, "error creating vfs ", 0);
       
   902         return TCL_ERROR;
       
   903       }
       
   904       if( isDefault ){
       
   905         sqlite3_vfs_register(p, 1);
       
   906       }
       
   907       Tcl_SetObjResult(interp, objv[2]);
       
   908       break;
       
   909     }
       
   910     case IV_BINARYLOG: {
       
   911       char *zName = 0;
       
   912       char *zLog = 0;
       
   913       char *zParent = 0;
       
   914       sqlite3_vfs *p;
       
   915       int isDefault = 0;
       
   916       int isLogdata = 0;
       
   917       int argbase = 2;
       
   918 
       
   919       for(argbase=2; argbase<(objc-2); argbase++){
       
   920         if( 0==strcmp("-default", Tcl_GetString(objv[argbase])) ){
       
   921           isDefault = 1;
       
   922         }
       
   923         else if( 0==strcmp("-parent", Tcl_GetString(objv[argbase])) ){
       
   924           argbase++;
       
   925           zParent = Tcl_GetString(objv[argbase]);
       
   926         }
       
   927         else if( 0==strcmp("-logdata", Tcl_GetString(objv[argbase])) ){
       
   928           isLogdata = 1;
       
   929         }else{
       
   930           break;
       
   931         }
       
   932       }
       
   933 
       
   934       if( (objc-argbase)!=2 ){
       
   935         Tcl_WrongNumArgs(
       
   936             interp, 2, objv, "?-default? ?-parent VFS? ?-logdata? NAME LOGFILE"
       
   937         );
       
   938         return TCL_ERROR;
       
   939       }
       
   940       zName = Tcl_GetString(objv[argbase]);
       
   941       zLog = Tcl_GetString(objv[argbase+1]);
       
   942       p = sqlite3_instvfs_binarylog(zName, zParent, zLog, isLogdata);
       
   943       if( !p ){
       
   944         Tcl_AppendResult(interp, "error creating vfs ", 0);
       
   945         return TCL_ERROR;
       
   946       }
       
   947       if( isDefault ){
       
   948         sqlite3_vfs_register(p, 1);
       
   949       }
       
   950       Tcl_SetObjResult(interp, objv[2]);
       
   951       break;
       
   952     }
       
   953 
       
   954     case IV_MARKER: {
       
   955       sqlite3_vfs *p;
       
   956       if( objc!=4 ){
       
   957         Tcl_WrongNumArgs(interp, 2, objv, "VFS MARKER");
       
   958         return TCL_ERROR;
       
   959       }
       
   960       p = sqlite3_vfs_find(Tcl_GetString(objv[2]));
       
   961       if( !p || p->xOpen!=instOpen ){
       
   962         Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0);
       
   963         return TCL_ERROR;
       
   964       }
       
   965       sqlite3_instvfs_binarylog_marker(p, Tcl_GetString(objv[3]));
       
   966       Tcl_ResetResult(interp);
       
   967       break;
       
   968     }
       
   969 
       
   970     case IV_CONFIGURE: {
       
   971       InstVfsCall *pCall;
       
   972 
       
   973       sqlite3_vfs *p;
       
   974       if( objc!=4 ){
       
   975         Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
       
   976         return TCL_ERROR;
       
   977       }
       
   978       p = sqlite3_vfs_find(Tcl_GetString(objv[2]));
       
   979       if( !p || p->xOpen!=instOpen ){
       
   980         Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0);
       
   981         return TCL_ERROR;
       
   982       }
       
   983 
       
   984       if( strlen(Tcl_GetString(objv[3])) ){
       
   985         pCall = (InstVfsCall *)sqlite3_malloc(sizeof(InstVfsCall));
       
   986         pCall->interp = interp;
       
   987         pCall->pScript = Tcl_DuplicateObj(objv[3]);
       
   988         Tcl_IncrRefCount(pCall->pScript);
       
   989         sqlite3_instvfs_configure(p, 
       
   990             test_instvfs_xcall, (void *)pCall, test_instvfs_xdel
       
   991         );
       
   992       }else{
       
   993         sqlite3_instvfs_configure(p, 0, 0, 0);
       
   994       }
       
   995       break;
       
   996     }
       
   997 
       
   998     case IV_REPORT:
       
   999     case IV_DESTROY:
       
  1000     case IV_RESET: {
       
  1001       sqlite3_vfs *p;
       
  1002       if( objc!=3 ){
       
  1003         Tcl_WrongNumArgs(interp, 2, objv, "NAME");
       
  1004         return TCL_ERROR;
       
  1005       }
       
  1006       p = sqlite3_vfs_find(Tcl_GetString(objv[2]));
       
  1007       if( !p || p->xOpen!=instOpen ){
       
  1008         Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0);
       
  1009         return TCL_ERROR;
       
  1010       }
       
  1011 
       
  1012       if( ((enum IV_enum)iSub)==IV_DESTROY ){
       
  1013         sqlite3_instvfs_destroy(p);
       
  1014       }
       
  1015       if( ((enum IV_enum)iSub)==IV_RESET ){
       
  1016         sqlite3_instvfs_reset(p);
       
  1017       }
       
  1018       if( ((enum IV_enum)iSub)==IV_REPORT ){
       
  1019         int ii;
       
  1020         Tcl_Obj *pRet = Tcl_NewObj();
       
  1021 
       
  1022         const char *zName = (char *)1;
       
  1023         sqlite3_int64 nClick;
       
  1024         int nCall;
       
  1025         for(ii=1; zName; ii++){
       
  1026           sqlite3_instvfs_get(p, ii, &zName, &nClick, &nCall);
       
  1027           if( zName ){
       
  1028             Tcl_Obj *pElem = Tcl_NewObj();
       
  1029             Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zName, -1));
       
  1030             Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(nCall));
       
  1031             Tcl_ListObjAppendElement(0, pElem, Tcl_NewWideIntObj(nClick));
       
  1032             Tcl_ListObjAppendElement(0, pRet, pElem);
       
  1033           }
       
  1034         }
       
  1035 
       
  1036         Tcl_SetObjResult(interp, pRet);
       
  1037       }
       
  1038 
       
  1039       break;
       
  1040     }
       
  1041   }
       
  1042 
       
  1043   return TCL_OK;
       
  1044 }
       
  1045 #endif /* SQLITE_ENABLE_INSTVFS */
       
  1046 
       
  1047 /* Alternative implementation of sqlite3_instvfs when the real
       
  1048 ** implementation is unavailable. 
       
  1049 */
       
  1050 #ifndef SQLITE_ENABLE_INSTVFS
       
  1051 static int test_sqlite3_instvfs(
       
  1052   void * clientData,
       
  1053   Tcl_Interp *interp,
       
  1054   int objc,
       
  1055   Tcl_Obj *CONST objv[]
       
  1056 ){
       
  1057   Tcl_AppendResult(interp, 
       
  1058      "not compiled with -DSQLITE_ENABLE_INSTVFS; sqlite3_instvfs is "
       
  1059      "unavailable", (char*)0);
       
  1060   return TCL_ERROR;
       
  1061 }
       
  1062 #endif /* !defined(SQLITE_ENABLE_INSTVFS) */
       
  1063 
       
  1064 int SqlitetestOsinst_Init(Tcl_Interp *interp){
       
  1065   Tcl_CreateObjCommand(interp, "sqlite3_instvfs", test_sqlite3_instvfs, 0, 0);
       
  1066   return TCL_OK;
       
  1067 }
       
  1068 
       
  1069 #endif /* SQLITE_TEST */