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 |