| OLD | NEW | 
 | (Empty) | 
|     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.19 2009/01/08 17:57:32 danielk1977 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, sq
      lite3_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 *pVfs, void *p, const char*zSym))(void); |  | 
|   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->pRe
      al)); |  | 
|   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 *p, const char *zSym))(void){ |  | 
|   461   return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym); |  | 
|   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", "binary
      log", "marker", 0 }; |  | 
|   874   enum IV_enum { IV_CREATE, IV_DESTROY, IV_RESET, IV_REPORT, IV_CONFIGURE, IV_BI
      NARYLOG, 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 */ |  | 
| OLD | NEW |