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