blob: a05ef7aa237c6b4b5d695bf683590d1eed2eebfd [file] [log] [blame]
danielk19775d1f5aa2008-04-10 14:51:00 +00001/*
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.
danielk1977822a5162008-05-16 04:51:54 +000016**
drh40f2c762008-07-25 13:32:44 +000017** $Id: test_osinst.c,v 1.18 2008/07/25 13:32:45 drh Exp $
danielk19775d1f5aa2008-04-10 14:51:00 +000018*/
danielk19775d1f5aa2008-04-10 14:51:00 +000019
drh40f2c762008-07-25 13:32:44 +000020#ifdef SQLITE_ENABLE_INSTVFS
danielk19775d1f5aa2008-04-10 14:51:00 +000021/*
danielk197770b9b042008-04-12 10:53:11 +000022** C interface:
danielk19775d1f5aa2008-04-10 14:51:00 +000023**
24** sqlite3_instvfs_create()
25** sqlite3_instvfs_destroy()
26** sqlite3_instvfs_configure()
27**
28** sqlite3_instvfs_reset()
29** sqlite3_instvfs_get()
30**
danielk197770b9b042008-04-12 10:53:11 +000031** sqlite3_instvfs_binarylog
danielk1977374177e2008-05-08 15:58:06 +000032** sqlite3_instvfs_binarylog_marker
danielk197770b9b042008-04-12 10:53:11 +000033**
34** Tcl interface (omitted if SQLITE_TEST is not set):
danielk19775d1f5aa2008-04-10 14:51:00 +000035**
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**
shane9bcbdad2008-05-29 20:22:37 +000057** * The time consumed by the method call as measured by
58** sqlite3Hwtime() (an integer value)
danielk19775d1f5aa2008-04-10 14:51:00 +000059**
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
shane9bcbdad2008-05-29 20:22:37 +000086** measured by sqlite3Hwtime() (an integer).
danielk19775d1f5aa2008-04-10 14:51:00 +000087*/
88
89#include "sqlite3.h"
danielk19770520dbb2008-04-12 11:30:12 +000090#include <string.h>
91#include <assert.h>
danielk19775d1f5aa2008-04-10 14:51:00 +000092
93/*
94** Maximum pathname length supported by the inst backend.
95*/
96#define INST_MAX_PATHNAME 512
97
98
99/* File methods */
danielk19775d1f5aa2008-04-10 14:51:00 +0000100/* Vfs methods */
danielk197770b9b042008-04-12 10:53:11 +0000101#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
danielk197770b9b042008-04-12 10:53:11 +0000110#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
danielk19775d1f5aa2008-04-10 14:51:00 +0000120
121#define OS_NUMEVENTS 21
122
danielk1977374177e2008-05-08 15:58:06 +0000123#define BINARYLOG_STRING 30
124#define BINARYLOG_MARKER 31
125
danielk1977d1868542008-06-11 11:00:31 +0000126#define BINARYLOG_PREPARE_V2 64
127#define BINARYLOG_STEP 65
128#define BINARYLOG_FINALIZE 66
129
danielk19775d1f5aa2008-04-10 14:51:00 +0000130struct InstVfs {
131 sqlite3_vfs base;
132 sqlite3_vfs *pVfs;
danielk1977374177e2008-05-08 15:58:06 +0000133
danielk19775d1f5aa2008-04-10 14:51:00 +0000134 void *pClient;
135 void (*xDel)(void *);
danielk1977374177e2008-05-08 15:58:06 +0000136 void (*xCall)(void *, int, int, sqlite3_int64, int, const char *, int, int, sqlite3_int64);
danielk19775d1f5aa2008-04-10 14:51:00 +0000137
138 /* Counters */
danielk19770520dbb2008-04-12 11:30:12 +0000139 sqlite3_int64 aTime[OS_NUMEVENTS];
danielk19775d1f5aa2008-04-10 14:51:00 +0000140 int aCount[OS_NUMEVENTS];
danielk1977374177e2008-05-08 15:58:06 +0000141
142 int iNextFileId;
danielk19775d1f5aa2008-04-10 14:51:00 +0000143};
144typedef struct InstVfs InstVfs;
145
146#define REALVFS(p) (((InstVfs *)(p))->pVfs)
147
148typedef struct inst_file inst_file;
149struct inst_file {
150 sqlite3_file base;
151 sqlite3_file *pReal;
152 InstVfs *pInstVfs;
153 const char *zName;
danielk1977374177e2008-05-08 15:58:06 +0000154 int iFileId; /* File id number */
danielk197770b9b042008-04-12 10:53:11 +0000155 int flags;
danielk19775d1f5aa2008-04-10 14:51:00 +0000156};
157
158/*
159** Method declarations for inst_file.
160*/
161static int instClose(sqlite3_file*);
162static int instRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
163static int instWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
164static int instTruncate(sqlite3_file*, sqlite3_int64 size);
165static int instSync(sqlite3_file*, int flags);
166static int instFileSize(sqlite3_file*, sqlite3_int64 *pSize);
167static int instLock(sqlite3_file*, int);
168static int instUnlock(sqlite3_file*, int);
danielk1977861f7452008-06-05 11:39:11 +0000169static int instCheckReservedLock(sqlite3_file*, int *pResOut);
danielk19775d1f5aa2008-04-10 14:51:00 +0000170static int instFileControl(sqlite3_file*, int op, void *pArg);
171static int instSectorSize(sqlite3_file*);
172static int instDeviceCharacteristics(sqlite3_file*);
173
174/*
175** Method declarations for inst_vfs.
176*/
177static int instOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
178static int instDelete(sqlite3_vfs*, const char *zName, int syncDir);
danielk1977861f7452008-06-05 11:39:11 +0000179static int instAccess(sqlite3_vfs*, const char *zName, int flags, int *);
danielk19775d1f5aa2008-04-10 14:51:00 +0000180static int instFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
181static void *instDlOpen(sqlite3_vfs*, const char *zFilename);
182static void instDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
183static void *instDlSym(sqlite3_vfs*,void*, const char *zSymbol);
184static void instDlClose(sqlite3_vfs*, void*);
185static int instRandomness(sqlite3_vfs*, int nByte, char *zOut);
186static int instSleep(sqlite3_vfs*, int microseconds);
187static int instCurrentTime(sqlite3_vfs*, double*);
188
danielk197727467042008-05-12 07:42:20 +0000189static void binarylog_blob(sqlite3_vfs *, const char *, int, int);
danielk1977374177e2008-05-08 15:58:06 +0000190
danielk19775d1f5aa2008-04-10 14:51:00 +0000191static 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 */
danielk19775d1f5aa2008-04-10 14:51:00 +0000201 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
211static 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
shane9bcbdad2008-05-29 20:22:37 +0000227/*
228** hwtime.h contains inline assembler code for implementing
229** high-performance timing routines.
danielk19775d1f5aa2008-04-10 14:51:00 +0000230*/
shane9bcbdad2008-05-29 20:22:37 +0000231#include "hwtime.h"
danielk19775d1f5aa2008-04-10 14:51:00 +0000232
233#define OS_TIME_IO(eEvent, A, B, Call) { \
234 inst_file *p = (inst_file *)pFile; \
235 InstVfs *pInstVfs = p->pInstVfs; \
236 int rc; \
shane9bcbdad2008-05-29 20:22:37 +0000237 sqlite_uint64 t = sqlite3Hwtime(); \
danielk19775d1f5aa2008-04-10 14:51:00 +0000238 rc = Call; \
shane9bcbdad2008-05-29 20:22:37 +0000239 t = sqlite3Hwtime() - t; \
danielk19775d1f5aa2008-04-10 14:51:00 +0000240 pInstVfs->aTime[eEvent] += t; \
241 pInstVfs->aCount[eEvent] += 1; \
242 if( pInstVfs->xCall ){ \
danielk1977374177e2008-05-08 15:58:06 +0000243 pInstVfs->xCall( \
244 pInstVfs->pClient,eEvent,p->iFileId,t,rc,p->zName,p->flags,A,B \
245 ); \
danielk19775d1f5aa2008-04-10 14:51:00 +0000246 } \
247 return rc; \
248}
249
danielk19772551caf2008-04-12 16:03:37 +0000250#define OS_TIME_VFS(eEvent, Z, flags, A, B, Call) { \
danielk19775d1f5aa2008-04-10 14:51:00 +0000251 InstVfs *pInstVfs = (InstVfs *)pVfs; \
252 int rc; \
shane9bcbdad2008-05-29 20:22:37 +0000253 sqlite_uint64 t = sqlite3Hwtime(); \
danielk19775d1f5aa2008-04-10 14:51:00 +0000254 rc = Call; \
shane9bcbdad2008-05-29 20:22:37 +0000255 t = sqlite3Hwtime() - t; \
danielk19775d1f5aa2008-04-10 14:51:00 +0000256 pInstVfs->aTime[eEvent] += t; \
257 pInstVfs->aCount[eEvent] += 1; \
258 if( pInstVfs->xCall ){ \
danielk1977374177e2008-05-08 15:58:06 +0000259 pInstVfs->xCall(pInstVfs->pClient,eEvent,0, t, rc, Z, flags, A, B); \
danielk19775d1f5aa2008-04-10 14:51:00 +0000260 } \
261 return rc; \
262}
263
264/*
265** Close an inst-file.
266*/
267static int instClose(sqlite3_file *pFile){
danielk1977d1868542008-06-11 11:00:31 +0000268 OS_TIME_IO(OS_CLOSE, 0, 0,
269 (p->pReal->pMethods ? p->pReal->pMethods->xClose(p->pReal) : SQLITE_OK)
270 );
danielk19775d1f5aa2008-04-10 14:51:00 +0000271}
272
273/*
274** Read data from an inst-file.
275*/
276static int instRead(
277 sqlite3_file *pFile,
278 void *zBuf,
279 int iAmt,
280 sqlite_int64 iOfst
281){
danielk197727467042008-05-12 07:42:20 +0000282 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 );
danielk19775d1f5aa2008-04-10 14:51:00 +0000286}
287
288/*
289** Write data to an inst-file.
290*/
291static int instWrite(
292 sqlite3_file *pFile,
293 const void *z,
294 int iAmt,
295 sqlite_int64 iOfst
296){
danielk197727467042008-05-12 07:42:20 +0000297 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 );
danielk19775d1f5aa2008-04-10 14:51:00 +0000302}
303
304/*
305** Truncate an inst-file.
306*/
307static int instTruncate(sqlite3_file *pFile, sqlite_int64 size){
danielk197793f7af92008-05-09 16:57:50 +0000308 OS_TIME_IO(OS_TRUNCATE, 0, (int)size,
309 p->pReal->pMethods->xTruncate(p->pReal, size)
310 );
danielk19775d1f5aa2008-04-10 14:51:00 +0000311}
312
313/*
314** Sync an inst-file.
315*/
316static int instSync(sqlite3_file *pFile, int flags){
danielk19770520dbb2008-04-12 11:30:12 +0000317 OS_TIME_IO(OS_SYNC, flags, 0, p->pReal->pMethods->xSync(p->pReal, flags));
danielk19775d1f5aa2008-04-10 14:51:00 +0000318}
319
320/*
321** Return the current file-size of an inst-file.
322*/
323static int instFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
danielk1977374177e2008-05-08 15:58:06 +0000324 OS_TIME_IO(OS_FILESIZE, (int)(*pSize), 0,
325 p->pReal->pMethods->xFileSize(p->pReal, pSize)
326 );
danielk19775d1f5aa2008-04-10 14:51:00 +0000327}
328
329/*
330** Lock an inst-file.
331*/
332static int instLock(sqlite3_file *pFile, int eLock){
danielk19770520dbb2008-04-12 11:30:12 +0000333 OS_TIME_IO(OS_LOCK, eLock, 0, p->pReal->pMethods->xLock(p->pReal, eLock));
danielk19775d1f5aa2008-04-10 14:51:00 +0000334}
335
336/*
337** Unlock an inst-file.
338*/
339static int instUnlock(sqlite3_file *pFile, int eLock){
danielk19770520dbb2008-04-12 11:30:12 +0000340 OS_TIME_IO(OS_UNLOCK, eLock, 0, p->pReal->pMethods->xUnlock(p->pReal, eLock));
danielk19775d1f5aa2008-04-10 14:51:00 +0000341}
342
343/*
344** Check if another file-handle holds a RESERVED lock on an inst-file.
345*/
danielk1977861f7452008-06-05 11:39:11 +0000346static int instCheckReservedLock(sqlite3_file *pFile, int *pResOut){
347 OS_TIME_IO(OS_CHECKRESERVEDLOCK, 0, 0,
348 p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut)
349 );
danielk19775d1f5aa2008-04-10 14:51:00 +0000350}
351
352/*
353** File control method. For custom operations on an inst-file.
354*/
355static int instFileControl(sqlite3_file *pFile, int op, void *pArg){
danielk19770520dbb2008-04-12 11:30:12 +0000356 OS_TIME_IO(OS_FILECONTROL, 0, 0, p->pReal->pMethods->xFileControl(p->pReal, op, pArg));
danielk19775d1f5aa2008-04-10 14:51:00 +0000357}
358
359/*
360** Return the sector-size in bytes for an inst-file.
361*/
362static int instSectorSize(sqlite3_file *pFile){
danielk19770520dbb2008-04-12 11:30:12 +0000363 OS_TIME_IO(OS_SECTORSIZE, 0, 0, p->pReal->pMethods->xSectorSize(p->pReal));
danielk19775d1f5aa2008-04-10 14:51:00 +0000364}
365
366/*
367** Return the device characteristic flags supported by an inst-file.
368*/
369static int instDeviceCharacteristics(sqlite3_file *pFile){
danielk19770520dbb2008-04-12 11:30:12 +0000370 OS_TIME_IO(OS_DEVCHAR, 0, 0, p->pReal->pMethods->xDeviceCharacteristics(p->pReal));
danielk19775d1f5aa2008-04-10 14:51:00 +0000371}
372
373/*
374** Open an inst file handle.
375*/
376static 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;
danielk197770b9b042008-04-12 10:53:11 +0000388 p->flags = flags;
danielk1977374177e2008-05-08 15:58:06 +0000389 p->iFileId = ++p->pInstVfs->iNextFileId;
danielk19775d1f5aa2008-04-10 14:51:00 +0000390
danielk197727467042008-05-12 07:42:20 +0000391 binarylog_blob(pVfs, zName, -1, 0);
danielk1977374177e2008-05-08 15:58:06 +0000392 OS_TIME_VFS(OS_OPEN, zName, flags, p->iFileId, 0,
danielk19770520dbb2008-04-12 11:30:12 +0000393 REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags)
danielk19775d1f5aa2008-04-10 14:51:00 +0000394 );
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*/
402static int instDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
danielk197727467042008-05-12 07:42:20 +0000403 binarylog_blob(pVfs, zPath, -1, 0);
danielk19772551caf2008-04-12 16:03:37 +0000404 OS_TIME_VFS(OS_DELETE, zPath, 0, dirSync, 0,
danielk19770520dbb2008-04-12 11:30:12 +0000405 REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync)
danielk19775d1f5aa2008-04-10 14:51:00 +0000406 );
407}
408
409/*
410** Test for access permissions. Return true if the requested permission
411** is available, or false otherwise.
412*/
danielk1977861f7452008-06-05 11:39:11 +0000413static int instAccess(
414 sqlite3_vfs *pVfs,
415 const char *zPath,
416 int flags,
417 int *pResOut
418){
danielk197727467042008-05-12 07:42:20 +0000419 binarylog_blob(pVfs, zPath, -1, 0);
danielk1977861f7452008-06-05 11:39:11 +0000420 OS_TIME_VFS(OS_ACCESS, zPath, 0, flags, *pResOut,
421 REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut)
danielk19775d1f5aa2008-04-10 14:51:00 +0000422 );
423}
424
425/*
danielk19775d1f5aa2008-04-10 14:51:00 +0000426** 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*/
430static int instFullPathname(
431 sqlite3_vfs *pVfs,
432 const char *zPath,
433 int nOut,
434 char *zOut
435){
danielk19772551caf2008-04-12 16:03:37 +0000436 OS_TIME_VFS( OS_FULLPATHNAME, zPath, 0, 0, 0,
danielk19770520dbb2008-04-12 11:30:12 +0000437 REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut);
danielk19775d1f5aa2008-04-10 14:51:00 +0000438 );
439}
440
441/*
442** Open the dynamic library located at zPath and return a handle.
443*/
444static void *instDlOpen(sqlite3_vfs *pVfs, const char *zPath){
danielk19770520dbb2008-04-12 11:30:12 +0000445 return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath);
danielk19775d1f5aa2008-04-10 14:51:00 +0000446}
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*/
453static void instDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
danielk19770520dbb2008-04-12 11:30:12 +0000454 REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
danielk19775d1f5aa2008-04-10 14:51:00 +0000455}
456
457/*
458** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
459*/
460static void *instDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
danielk19770520dbb2008-04-12 11:30:12 +0000461 return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), pHandle, zSymbol);
danielk19775d1f5aa2008-04-10 14:51:00 +0000462}
463
464/*
465** Close the dynamic library handle pHandle.
466*/
467static void instDlClose(sqlite3_vfs *pVfs, void *pHandle){
danielk19770520dbb2008-04-12 11:30:12 +0000468 REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle);
danielk19775d1f5aa2008-04-10 14:51:00 +0000469}
470
471/*
472** Populate the buffer pointed to by zBufOut with nByte bytes of
473** random data.
474*/
475static int instRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
danielk19772551caf2008-04-12 16:03:37 +0000476 OS_TIME_VFS( OS_RANDOMNESS, 0, 0, nByte, 0,
danielk19770520dbb2008-04-12 11:30:12 +0000477 REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut);
danielk19775d1f5aa2008-04-10 14:51:00 +0000478 );
479}
480
481/*
482** Sleep for nMicro microseconds. Return the number of microseconds
483** actually slept.
484*/
485static int instSleep(sqlite3_vfs *pVfs, int nMicro){
danielk19772551caf2008-04-12 16:03:37 +0000486 OS_TIME_VFS( OS_SLEEP, 0, 0, nMicro, 0,
danielk19770520dbb2008-04-12 11:30:12 +0000487 REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro)
danielk19775d1f5aa2008-04-10 14:51:00 +0000488 );
489}
490
491/*
492** Return the current time as a Julian Day number in *pTimeOut.
493*/
494static int instCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
danielk19772551caf2008-04-12 16:03:37 +0000495 OS_TIME_VFS( OS_CURRENTTIME, 0, 0, 0, 0,
danielk19770520dbb2008-04-12 11:30:12 +0000496 REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut)
danielk19775d1f5aa2008-04-10 14:51:00 +0000497 );
498}
499
danielk197770b9b042008-04-12 10:53:11 +0000500sqlite3_vfs *sqlite3_instvfs_create(const char *zName, const char *zParent){
danielk19775d1f5aa2008-04-10 14:51:00 +0000501 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
526void sqlite3_instvfs_configure(
527 sqlite3_vfs *pVfs,
danielk1977374177e2008-05-08 15:58:06 +0000528 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 ),
danielk19775d1f5aa2008-04-10 14:51:00 +0000539 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
552void sqlite3_instvfs_destroy(sqlite3_vfs *pVfs){
danielk19772551caf2008-04-12 16:03:37 +0000553 if( pVfs ){
554 sqlite3_vfs_unregister(pVfs);
555 sqlite3_instvfs_configure(pVfs, 0, 0, 0);
556 sqlite3_free(pVfs);
557 }
danielk19775d1f5aa2008-04-10 14:51:00 +0000558}
559
560void sqlite3_instvfs_reset(sqlite3_vfs *pVfs){
561 InstVfs *p = (InstVfs *)pVfs;
562 assert( pVfs->xOpen==instOpen );
danielk19770520dbb2008-04-12 11:30:12 +0000563 memset(p->aTime, 0, sizeof(sqlite3_int64)*OS_NUMEVENTS);
danielk19775d1f5aa2008-04-10 14:51:00 +0000564 memset(p->aCount, 0, sizeof(int)*OS_NUMEVENTS);
565}
566
567const 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;
danielk19775d1f5aa2008-04-10 14:51:00 +0000586 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
595void 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
danielk197727467042008-05-12 07:42:20 +0000616#define BINARYLOG_BUFFERSIZE 8192
danielk197770b9b042008-04-12 10:53:11 +0000617
618struct InstVfsBinaryLog {
619 int nBuf;
620 char *zBuf;
621 sqlite3_int64 iOffset;
danielk197727467042008-05-12 07:42:20 +0000622 int log_data;
danielk197770b9b042008-04-12 10:53:11 +0000623 sqlite3_file *pOut;
danielk19770520dbb2008-04-12 11:30:12 +0000624 char *zOut; /* Log file name */
danielk197770b9b042008-04-12 10:53:11 +0000625};
626typedef struct InstVfsBinaryLog InstVfsBinaryLog;
627
danielk19770520dbb2008-04-12 11:30:12 +0000628static void put32bits(unsigned char *p, unsigned int v){
danielk197770b9b042008-04-12 10:53:11 +0000629 p[0] = v>>24;
630 p[1] = v>>16;
631 p[2] = v>>8;
632 p[3] = v;
633}
634
danielk197793f7af92008-05-09 16:57:50 +0000635static 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
danielk197770b9b042008-04-12 10:53:11 +0000663static void binarylog_xcall(
664 void *p,
665 int eEvent,
danielk1977374177e2008-05-08 15:58:06 +0000666 int iFileId,
danielk197770b9b042008-04-12 10:53:11 +0000667 sqlite3_int64 nClick,
danielk1977374177e2008-05-08 15:58:06 +0000668 int return_code,
danielk197770b9b042008-04-12 10:53:11 +0000669 const char *zName,
670 int flags,
671 int nByte,
672 sqlite3_int64 iOffset
673){
674 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p;
675 unsigned char *zRec;
danielk1977374177e2008-05-08 15:58:06 +0000676 if( (28+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){
danielk197793f7af92008-05-09 16:57:50 +0000677 binarylog_flush(pLog);
danielk197770b9b042008-04-12 10:53:11 +0000678 }
679 zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf];
680 put32bits(&zRec[0], eEvent);
danielk1977374177e2008-05-08 15:58:06 +0000681 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;
danielk197770b9b042008-04-12 10:53:11 +0000688}
689
690static 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 ){
danielk197793f7af92008-05-09 16:57:50 +0000697 binarylog_flush(pLog);
danielk197770b9b042008-04-12 10:53:11 +0000698 }
699 pFile->pMethods->xClose(pFile);
danielk197730f72bf2008-04-14 17:42:41 +0000700 sqlite3_free(pLog->pOut);
danielk197770b9b042008-04-12 10:53:11 +0000701 sqlite3_free(pLog->zBuf);
702 sqlite3_free(pLog);
703}
704
danielk1977374177e2008-05-08 15:58:06 +0000705static void binarylog_blob(
706 sqlite3_vfs *pVfs,
707 const char *zBlob,
danielk197727467042008-05-12 07:42:20 +0000708 int nBlob,
709 int isBinary
danielk1977374177e2008-05-08 15:58:06 +0000710){
danielk1977374177e2008-05-08 15:58:06 +0000711 InstVfsBinaryLog *pLog;
danielk197727467042008-05-12 07:42:20 +0000712 InstVfs *pInstVfs = (InstVfs *)pVfs;
danielk1977374177e2008-05-08 15:58:06 +0000713
714 if( pVfs->xOpen!=instOpen || pInstVfs->xCall!=binarylog_xcall ){
715 return;
716 }
danielk1977374177e2008-05-08 15:58:06 +0000717 pLog = (InstVfsBinaryLog *)pInstVfs->pClient;
danielk1977185eac92008-07-12 15:55:54 +0000718 if( zBlob && (!isBinary || pLog->log_data) ){
danielk197727467042008-05-12 07:42:20 +0000719 unsigned char *zRec;
720 int nWrite;
danielk1977374177e2008-05-08 15:58:06 +0000721
danielk197727467042008-05-12 07:42:20 +0000722 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;
danielk1977374177e2008-05-08 15:58:06 +0000738 }
danielk1977374177e2008-05-08 15:58:06 +0000739}
740
danielk1977d1868542008-06-11 11:00:31 +0000741void 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
danielk1977374177e2008-05-08 15:58:06 +0000757void sqlite3_instvfs_binarylog_marker(
758 sqlite3_vfs *pVfs,
759 const char *zMarker
760){
761 InstVfs *pInstVfs = (InstVfs *)pVfs;
762 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)pInstVfs->pClient;
danielk197727467042008-05-12 07:42:20 +0000763 binarylog_blob(pVfs, zMarker, -1, 0);
danielk1977374177e2008-05-08 15:58:06 +0000764 binarylog_xcall(pLog, BINARYLOG_MARKER, 0, 0, 0, 0, 0, 0, 0);
765}
766
danielk197770b9b042008-04-12 10:53:11 +0000767sqlite3_vfs *sqlite3_instvfs_binarylog(
768 const char *zVfs,
769 const char *zParentVfs,
danielk197727467042008-05-12 07:42:20 +0000770 const char *zLog,
771 int log_data
danielk197770b9b042008-04-12 10:53:11 +0000772){
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
danielk197730f72bf2008-04-14 17:42:41 +0000785 nByte = sizeof(InstVfsBinaryLog) + pParent->mxPathname+1;
danielk197770b9b042008-04-12 10:53:11 +0000786 p = (InstVfsBinaryLog *)sqlite3_malloc(nByte);
787 memset(p, 0, nByte);
788 p->zBuf = sqlite3_malloc(BINARYLOG_BUFFERSIZE);
danielk19770520dbb2008-04-12 11:30:12 +0000789 p->zOut = (char *)&p[1];
danielk197730f72bf2008-04-14 17:42:41 +0000790 p->pOut = (sqlite3_file *)sqlite3_malloc(pParent->szOsFile);
danielk197727467042008-05-12 07:42:20 +0000791 p->log_data = log_data;
danielk19770520dbb2008-04-12 11:30:12 +0000792 pParent->xFullPathname(pParent, zLog, pParent->mxPathname, p->zOut);
danielk197770b9b042008-04-12 10:53:11 +0000793 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL;
danielk19772551caf2008-04-12 16:03:37 +0000794 pParent->xDelete(pParent, p->zOut, 0);
danielk19770520dbb2008-04-12 11:30:12 +0000795 rc = pParent->xOpen(pParent, p->zOut, p->pOut, flags, &flags);
danielk197770b9b042008-04-12 10:53:11 +0000796 if( rc==SQLITE_OK ){
danielk197793f7af92008-05-09 16:57:50 +0000797 memcpy(p->zBuf, "sqlite_ostrace1.....", 20);
798 p->iOffset = 0;
799 p->nBuf = 20;
danielk197770b9b042008-04-12 10:53:11 +0000800 }
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}
drh40f2c762008-07-25 13:32:44 +0000813#endif /* SQLITE_ENABLE_INSTVFS */
danielk197770b9b042008-04-12 10:53:11 +0000814
danielk19775d1f5aa2008-04-10 14:51:00 +0000815/**************************************************************************
816***************************************************************************
817** Tcl interface starts here.
818*/
danielk197770b9b042008-04-12 10:53:11 +0000819#if SQLITE_TEST
danielk19775d1f5aa2008-04-10 14:51:00 +0000820
821#include <tcl.h>
822
drh40f2c762008-07-25 13:32:44 +0000823#ifdef SQLITE_ENABLE_INSTVFS
danielk19775d1f5aa2008-04-10 14:51:00 +0000824struct InstVfsCall {
825 Tcl_Interp *interp;
826 Tcl_Obj *pScript;
827};
828typedef struct InstVfsCall InstVfsCall;
829
830static void test_instvfs_xcall(
831 void *p,
832 int eEvent,
danielk1977374177e2008-05-08 15:58:06 +0000833 int iFileId,
danielk19775d1f5aa2008-04-10 14:51:00 +0000834 sqlite3_int64 nClick,
danielk1977374177e2008-05-08 15:58:06 +0000835 int return_code,
danielk19775d1f5aa2008-04-10 14:51:00 +0000836 const char *zName,
danielk197770b9b042008-04-12 10:53:11 +0000837 int flags,
danielk19775d1f5aa2008-04-10 14:51:00 +0000838 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
860static void test_instvfs_xdel(void *p){
861 InstVfsCall *pCall = (InstVfsCall *)p;
862 Tcl_DecrRefCount(pCall->pScript);
863 sqlite3_free(pCall);
864}
865
866static 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[] =
danielk1977374177e2008-05-08 15:58:06 +0000873 { "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 };
danielk19775d1f5aa2008-04-10 14:51:00 +0000875 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;
danielk19771e21fd52008-04-10 17:27:38 +0000888 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?");
danielk19775d1f5aa2008-04-10 14:51:00 +0000894 return TCL_ERROR;
895 }
danielk19771e21fd52008-04-10 17:27:38 +0000896 if( objc==(4+isDefault) ){
897 zParent = Tcl_GetString(objv[3+isDefault]);
danielk19775d1f5aa2008-04-10 14:51:00 +0000898 }
danielk19771e21fd52008-04-10 17:27:38 +0000899 p = sqlite3_instvfs_create(Tcl_GetString(objv[2+isDefault]), zParent);
danielk19775d1f5aa2008-04-10 14:51:00 +0000900 if( !p ){
901 Tcl_AppendResult(interp, "error creating vfs ", 0);
902 return TCL_ERROR;
903 }
danielk19771e21fd52008-04-10 17:27:38 +0000904 if( isDefault ){
905 sqlite3_vfs_register(p, 1);
906 }
danielk19775d1f5aa2008-04-10 14:51:00 +0000907 Tcl_SetObjResult(interp, objv[2]);
908 break;
909 }
danielk197770b9b042008-04-12 10:53:11 +0000910 case IV_BINARYLOG: {
911 char *zName = 0;
912 char *zLog = 0;
danielk197793f7af92008-05-09 16:57:50 +0000913 char *zParent = 0;
danielk197770b9b042008-04-12 10:53:11 +0000914 sqlite3_vfs *p;
915 int isDefault = 0;
danielk197727467042008-05-12 07:42:20 +0000916 int isLogdata = 0;
danielk197793f7af92008-05-09 16:57:50 +0000917 int argbase = 2;
918
danielk197727467042008-05-12 07:42:20 +0000919 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 }
danielk197793f7af92008-05-09 16:57:50 +0000932 }
933
934 if( (objc-argbase)!=2 ){
935 Tcl_WrongNumArgs(
danielk197727467042008-05-12 07:42:20 +0000936 interp, 2, objv, "?-default? ?-parent VFS? ?-logdata? NAME LOGFILE"
danielk197793f7af92008-05-09 16:57:50 +0000937 );
danielk197770b9b042008-04-12 10:53:11 +0000938 return TCL_ERROR;
939 }
danielk197793f7af92008-05-09 16:57:50 +0000940 zName = Tcl_GetString(objv[argbase]);
941 zLog = Tcl_GetString(objv[argbase+1]);
danielk197727467042008-05-12 07:42:20 +0000942 p = sqlite3_instvfs_binarylog(zName, zParent, zLog, isLogdata);
danielk197770b9b042008-04-12 10:53:11 +0000943 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 }
danielk19775d1f5aa2008-04-10 14:51:00 +0000953
danielk1977374177e2008-05-08 15:58:06 +0000954 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
danielk19775d1f5aa2008-04-10 14:51:00 +0000970 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;
danielk19770520dbb2008-04-12 11:30:12 +00001023 sqlite3_int64 nClick;
danielk19775d1f5aa2008-04-10 14:51:00 +00001024 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}
drh40f2c762008-07-25 13:32:44 +00001045#endif /* SQLITE_ENABLE_INSTVFS */
1046
1047/* Alternative implementation of sqlite3_instvfs when the real
1048** implementation is unavailable.
1049*/
1050#ifndef SQLITE_ENABLE_INSTVFS
1051static 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) */
danielk19775d1f5aa2008-04-10 14:51:00 +00001063
1064int SqlitetestOsinst_Init(Tcl_Interp *interp){
1065 Tcl_CreateObjCommand(interp, "sqlite3_instvfs", test_sqlite3_instvfs, 0, 0);
1066 return TCL_OK;
1067}
1068
drh40f2c762008-07-25 13:32:44 +00001069#endif /* SQLITE_TEST */