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