Index: Makefile.in ================================================================== --- Makefile.in +++ Makefile.in @@ -375,10 +375,12 @@ parse.c \ parse.h \ config.h \ shell.c \ sqlite3.h + +SRC += $(TOP)/src/test_osinst.c # Source code to the test files. # TESTSRC = \ $(TOP)/src/test1.c \ @@ -679,10 +681,13 @@ sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS) dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS) + +osinst2sql$(TEXE): $(TOP)/tool/osinst2sql.c sqlite3.c sqlite3.h + $(LTLINK) -o $@ $(TOP)/tool/osinst2sql.c sqlite3.c $(TLIBS) DBFUZZ2_OPTS = \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_ENABLE_DESERIALIZE \ Index: Makefile.msc ================================================================== --- Makefile.msc +++ Makefile.msc @@ -1344,11 +1344,12 @@ $(TOP)\src\wal.c \ $(TOP)\src\walker.c \ $(TOP)\src\where.c \ $(TOP)\src\wherecode.c \ $(TOP)\src\whereexpr.c \ - $(TOP)\src\window.c + $(TOP)\src\window.c \ + $(TOP)\src\test_osinst.c # Core miscellaneous files. # SRC03 = \ $(TOP)\src\parse.y @@ -1468,11 +1469,11 @@ SRC12 = !ENDIF # All source code files. # -SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) +SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) # Source code to the test files. # TESTSRC = \ $(TOP)\src\test1.c \ @@ -1770,10 +1771,13 @@ $(LTLINK) $(NO_WARN) $(FUZZERSHELL_COMPILE_OPTS) $(TOP)\tool\fuzzershell.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) dbfuzz.exe: $(TOP)\test\dbfuzz.c $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(DBFUZZ_COMPILE_OPTS) $(TOP)\test\dbfuzz.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) +osinst2sql.exe: $(TOP)\tool\osinst2sql.c $(SQLITE3C) $(SQLITE3H) + $(LTLINK) $(NO_WARN) $(TOP)\tool\osinst2sql.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) + fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) ossshell.exe: $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H) $(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) Index: main.mk ================================================================== --- main.mk +++ main.mk @@ -295,10 +295,12 @@ parse.c \ parse.h \ shell.c \ sqlite3.h +SRC += $(TOP)/src/test_osinst.c + # Source code to the test files. # TESTSRC = \ $(TOP)/ext/expert/sqlite3expert.c \ @@ -577,10 +579,15 @@ dbfuzz$(EXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(TCCX) -o dbfuzz$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c \ $(TLIBS) $(THREADLIB) + +osinst2sql$(EXE): $(TOP)/tool/osinst2sql.c sqlite3.c sqlite3.h + $(TCCX) -o osinst2sql$(EXE) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION \ + $(DBFUZZ_OPT) $(TOP)/tool/osinst2sql.c sqlite3.c \ + $(TLIBS) $(THREADLIB) DBFUZZ2_OPTS = \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_OMIT_LOAD_EXTENSION \ -DSQLITE_ENABLE_DESERIALIZE \ Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -1145,10 +1145,15 @@ ** prepare statement or sqlite3_backup closes. */ int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); } int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); } +#ifdef SQLITE_ENABLE_OSINST +int sqlite3_vfslog_new(const char*,const char*,const char*,sqlite3_vfs**); +int sqlite3_vfslog_finalize(const char*); +#endif + /* ** Close the mutex on database connection db. ** ** Furthermore, if database connection db is a zombie (meaning that there @@ -1249,10 +1254,17 @@ sqlite3_free(db->auth.zAuthUser); sqlite3_free(db->auth.zAuthPW); #endif db->magic = SQLITE_MAGIC_ERROR; + +#ifdef SQLITE_ENABLE_OSINST + if( db->pOsinstVfs ){ + sqlite3_vfslog_finalize(db->pOsinstVfs->zName); + db->pOsinstVfs = 0; + } +#endif /* The temp-database schema is allocated differently from the other schema ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). ** So it needs to be freed here. Todo: Why not roll the temp schema into ** the same sqliteMalloc() as the one that allocates the database @@ -3185,16 +3197,36 @@ if( ((1<<(flags&7)) & 0x46)==0 ){ rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */ }else{ rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); } +#ifdef SQLITE_ENABLE_OSINST + /* If this is not a temporary or ":memory:" database, create an osinst + ** VFS to use. */ + assert( db->pVfs ); + if( rc==SQLITE_OK && zOpen && zOpen[0] && strcmp(":memory:", zOpen) ){ + u32 iVal = 0; + char *zLog = 0; + sqlite3_randomness(sizeof(iVal), (void*)&iVal); + zLog = sqlite3_mprintf("%s-osinst-%08x", zOpen, iVal); + if( zLog==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + sqlite3_vfs *pVfs = 0; + rc = sqlite3_vfslog_new(zLog, db->pVfs->zName, zLog, &pVfs); + sqlite3_free(zLog); + db->pOsinstVfs = db->pVfs = pVfs; + } + } +#endif if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg); sqlite3_free(zErrMsg); goto opendb_out; } + /* Open the backend database driver */ rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, flags | SQLITE_OPEN_MAIN_DB); if( rc!=SQLITE_OK ){ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -13,10 +13,12 @@ ** */ #ifndef SQLITEINT_H #define SQLITEINT_H +#define SQLITE_ENABLE_OSINST 1 + /* Special Comments: ** ** Some comments have special meaning to the tools that measure test ** coverage: ** @@ -1485,10 +1487,13 @@ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif #ifdef SQLITE_USER_AUTHENTICATION sqlite3_userauth auth; /* User authentication information */ #endif +#ifdef SQLITE_ENABLE_OSINST + sqlite3_vfs *pOsinstVfs; /* osinst VFS to finalize, if any */ +#endif }; /* ** A macro to discover the encoding of a database. */ Index: src/test_osinst.c ================================================================== --- src/test_osinst.c +++ src/test_osinst.c @@ -60,10 +60,11 @@ ** creates a virtual table with 6 columns, as follows: ** ** CREATE TABLE v( ** event TEXT, // "xOpen", "xRead" etc. ** file TEXT, // Name of file this call applies to +** time INTEGER, // Timestamp ** clicks INTEGER, // Time spent in call ** rc INTEGER, // Return value ** size INTEGER, // Bytes read or written ** offset INTEGER // File offset read or written ** ); @@ -245,27 +246,28 @@ static sqlite3_uint64 vfslog_time(){ return 0; } #endif -static void vfslog_call(sqlite3_vfs *, int, int, sqlite3_int64, int, int, int); +static void vfslog_call( +sqlite3_vfs *, int, int, sqlite3_uint64, sqlite3_int64, int, int, sqlite_int64); static void vfslog_string(sqlite3_vfs *, const char *); /* ** Close an vfslog-file. */ static int vfslogClose(sqlite3_file *pFile){ - sqlite3_uint64 t; + sqlite3_uint64 t, t2; int rc = SQLITE_OK; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); if( p->pReal->pMethods ){ rc = p->pReal->pMethods->xClose(p->pReal); } - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, rc, 0, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_CLOSE, p->iFileId, t, t2, rc, 0, 0); return rc; } /* ** Read data from an vfslog-file. @@ -275,16 +277,16 @@ void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, rc, iAmt, (int)iOfst); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_READ, p->iFileId, t, t2, rc, iAmt, iOfst); return rc; } /* ** Write data to an vfslog-file. @@ -294,100 +296,100 @@ const void *z, int iAmt, sqlite_int64 iOfst ){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, rc, iAmt, (int)iOfst); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_WRITE, p->iFileId, t, t2, rc, iAmt, iOfst); return rc; } /* ** Truncate an vfslog-file. */ static int vfslogTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xTruncate(p->pReal, size); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, rc, 0, (int)size); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_TRUNCATE, p->iFileId, t, t2, rc, 0, size); return rc; } /* ** Sync an vfslog-file. */ static int vfslogSync(sqlite3_file *pFile, int flags){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xSync(p->pReal, flags); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, rc, flags, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_SYNC, p->iFileId, t, t2, rc, flags, 0); return rc; } /* ** Return the current file-size of an vfslog-file. */ static int vfslogFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xFileSize(p->pReal, pSize); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, rc, 0, (int)*pSize); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_FILESIZE, p->iFileId, t, t2, rc, 0, *pSize); return rc; } /* ** Lock an vfslog-file. */ static int vfslogLock(sqlite3_file *pFile, int eLock){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xLock(p->pReal, eLock); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, rc, eLock, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_LOCK, p->iFileId, t, t2, rc, eLock, 0); return rc; } /* ** Unlock an vfslog-file. */ static int vfslogUnlock(sqlite3_file *pFile, int eLock){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xUnlock(p->pReal, eLock); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, rc, eLock, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_UNLOCK, p->iFileId, t, t2, rc, eLock, 0); return rc; } /* ** Check if another file-handle holds a RESERVED lock on an vfslog-file. */ static int vfslogCheckReservedLock(sqlite3_file *pFile, int *pResOut){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t, rc, *pResOut, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_CHECKRESERVEDLOCK, p->iFileId, t,t2,rc,*pResOut,0); return rc; } /* ** File control method. For custom operations on an vfslog-file. @@ -404,41 +406,41 @@ /* ** Return the sector-size in bytes for an vfslog-file. */ static int vfslogSectorSize(sqlite3_file *pFile){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xSectorSize(p->pReal); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, rc, 0, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_SECTORSIZE, p->iFileId, t, t2, rc, 0, 0); return rc; } /* ** Return the device characteristic flags supported by an vfslog-file. */ static int vfslogDeviceCharacteristics(sqlite3_file *pFile){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, rc, 0, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_DEVCHAR, p->iFileId, t, t2, rc, 0, 0); return rc; } static int vfslogShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, rc, 0, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_SHMLOCK, p->iFileId, t, t2, rc, 0, 0); return rc; } static int vfslogShmMap( sqlite3_file *pFile, int iRegion, @@ -445,34 +447,34 @@ int szRegion, int isWrite, volatile void **pp ){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, rc, 0, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_SHMMAP, p->iFileId, t, t2, rc, 0, 0); return rc; } static void vfslogShmBarrier(sqlite3_file *pFile){ - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); p->pReal->pMethods->xShmBarrier(p->pReal); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, SQLITE_OK, 0, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_SHMBARRIER, p->iFileId, t, t2, SQLITE_OK, 0, 0); } static int vfslogShmUnmap(sqlite3_file *pFile, int deleteFlag){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; t = vfslog_time(); rc = p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag); - t = vfslog_time() - t; - vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, rc, 0, 0); + t2 = vfslog_time() - t; + vfslog_call(p->pVfslog, OS_SHMUNMAP, p->iFileId, t, t2, rc, 0, 0); return rc; } /* @@ -484,11 +486,11 @@ sqlite3_file *pFile, int flags, int *pOutFlags ){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; VfslogFile *p = (VfslogFile *)pFile; VfslogVfs *pLog = (VfslogVfs *)pVfs; pFile->pMethods = &vfslog_io_methods; p->pReal = (sqlite3_file *)&p[1]; @@ -495,13 +497,13 @@ p->pVfslog = pVfs; p->iFileId = ++pLog->iNextFileId; t = vfslog_time(); rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags); - t = vfslog_time() - t; + t2 = vfslog_time() - t; - vfslog_call(pVfs, OS_OPEN, p->iFileId, t, rc, 0, 0); + vfslog_call(pVfs, OS_OPEN, p->iFileId, t, t2, rc, 0, 0); vfslog_string(pVfs, zName); return rc; } /* @@ -509,15 +511,15 @@ ** ensure the file-system modifications are synced to disk before ** returning. */ static int vfslogDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; t = vfslog_time(); rc = REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync); - t = vfslog_time() - t; - vfslog_call(pVfs, OS_DELETE, 0, t, rc, dirSync, 0); + t2 = vfslog_time() - t; + vfslog_call(pVfs, OS_DELETE, 0, t, t2, rc, dirSync, 0); vfslog_string(pVfs, zPath); return rc; } /* @@ -529,15 +531,15 @@ const char *zPath, int flags, int *pResOut ){ int rc; - sqlite3_uint64 t; + sqlite3_uint64 t, t2; t = vfslog_time(); rc = REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut); - t = vfslog_time() - t; - vfslog_call(pVfs, OS_ACCESS, 0, t, rc, flags, *pResOut); + t2 = vfslog_time() - t; + vfslog_call(pVfs, OS_ACCESS, 0, t, t2, rc, flags, (sqlite3_int64)*pResOut); vfslog_string(pVfs, zPath); return rc; } /* @@ -640,39 +642,49 @@ sqlite3_io_error_persist = persist; sqlite3_diskfull_pending = diskfull; #endif } -static void put32bits(unsigned char *p, unsigned int v){ +static void vfslogPut32bits(unsigned char *p, unsigned int v){ p[0] = v>>24; p[1] = (unsigned char)(v>>16); p[2] = (unsigned char)(v>>8); p[3] = (unsigned char)v; } +static void vfslogPut64bits(unsigned char *p, sqlite3_int64 v){ + vfslogPut32bits(p, (v >> 32) & 0xFFFFFFFF); + vfslogPut32bits(&p[4], v & 0xFFFFFFFF); +} + +#define VFSLOG_RECORD_SIZE 36 + static void vfslog_call( sqlite3_vfs *pVfs, int eEvent, int iFileid, + sqlite3_uint64 tStamp, sqlite3_int64 nClick, int return_code, int size, - int offset + sqlite3_int64 offset ){ VfslogVfs *p = (VfslogVfs *)pVfs; unsigned char *zRec; - if( (24+p->nBuf)>sizeof(p->aBuf) ){ + if( (VFSLOG_RECORD_SIZE+p->nBuf)>sizeof(p->aBuf) ){ vfslog_flush(p); } zRec = (unsigned char *)&p->aBuf[p->nBuf]; - put32bits(&zRec[0], eEvent); - put32bits(&zRec[4], iFileid); - put32bits(&zRec[8], (unsigned int)(nClick&0xffff)); - put32bits(&zRec[12], return_code); - put32bits(&zRec[16], size); - put32bits(&zRec[20], offset); - p->nBuf += 24; + vfslogPut32bits(&zRec[0], eEvent); + vfslogPut32bits(&zRec[4], iFileid); + vfslogPut64bits(&zRec[8], (sqlite3_int64)tStamp); + vfslogPut32bits(&zRec[16], (unsigned int)(nClick&0xffffffff)); + vfslogPut32bits(&zRec[20], return_code); + vfslogPut32bits(&zRec[24], size); + vfslogPut64bits(&zRec[28], offset); + + p->nBuf += VFSLOG_RECORD_SIZE; } static void vfslog_string(sqlite3_vfs *pVfs, const char *zStr){ VfslogVfs *p = (VfslogVfs *)pVfs; unsigned char *zRec; @@ -679,11 +691,11 @@ int nStr = zStr ? (int)strlen(zStr) : 0; if( (4+nStr+p->nBuf)>sizeof(p->aBuf) ){ vfslog_flush(p); } zRec = (unsigned char *)&p->aBuf[p->nBuf]; - put32bits(&zRec[0], nStr); + vfslogPut32bits(&zRec[0], nStr); if( zStr ){ memcpy(&zRec[4], zStr, nStr); } p->nBuf += (4 + nStr); } @@ -708,11 +720,12 @@ } int sqlite3_vfslog_new( const char *zVfs, /* New VFS name */ const char *zParentVfs, /* Parent VFS name (or NULL) */ - const char *zLog /* Log file name */ + const char *zLog, /* Log file name */ + sqlite3_vfs **ppVfs /* OUT: New VFS object */ ){ VfslogVfs *p; sqlite3_vfs *pParent; int nByte; int flags; @@ -745,25 +758,27 @@ rc = pParent->xOpen(pParent, zFile, p->pLog, flags, &flags); if( rc==SQLITE_OK ){ memcpy(p->aBuf, "sqlite_ostrace1.....", 20); p->iOffset = 0; p->nBuf = 20; - rc = sqlite3_vfs_register((sqlite3_vfs *)p, 1); + rc = sqlite3_vfs_register((sqlite3_vfs *)p, 0); + if( ppVfs ) *ppVfs = (sqlite3_vfs*)p; } if( rc ){ vfslog_finalize(p); } return rc; } int sqlite3_vfslog_annotate(const char *zVfs, const char *zMsg){ sqlite3_vfs *pVfs; + sqlite3_uint64 t = vfslog_time(); pVfs = sqlite3_vfs_find(zVfs); if( !pVfs || pVfs->xOpen!=vfslogOpen ){ return SQLITE_ERROR; } - vfslog_call(pVfs, OS_ANNOTATE, 0, 0, 0, 0, 0); + vfslog_call(pVfs, OS_ANNOTATE, 0, t, 0, 0, 0, 0); vfslog_string(pVfs, zMsg); return SQLITE_OK; } static const char *vfslog_eventname(int eEvent){ @@ -897,11 +912,11 @@ rc = pVfs->xOpen(pVfs, p->zFile, p->pFd, flags, &flags); if( rc==SQLITE_OK ){ p->pFd->pMethods->xFileSize(p->pFd, &p->nByte); sqlite3_declare_vtab(db, - "CREATE TABLE xxx(event, file, click, rc, size, offset)" + "CREATE TABLE xxx(event, file, time, click, rc, size, offset)" ); *ppVtab = &p->base; }else{ sqlite3_free(p); } @@ -969,11 +984,11 @@ int nRead; sqlite3_free(pCsr->zTransient); pCsr->zTransient = 0; - nRead = 24; + nRead = VFSLOG_RECORD_SIZE; if( pCsr->iOffset+nRead<=p->nByte ){ int eEvent; rc = p->pFd->pMethods->xRead(p->pFd, pCsr->aBuf, nRead, pCsr->iOffset); eEvent = get32bits(pCsr->aBuf); @@ -984,11 +999,13 @@ rc = p->pFd->pMethods->xRead(p->pFd, buf, 4, pCsr->iOffset+nRead); nRead += 4; if( rc==SQLITE_OK ){ int nStr = get32bits((unsigned char *)buf); char *zStr = sqlite3_malloc(nStr+1); - rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead); + if( nStr>0 ){ + rc = p->pFd->pMethods->xRead(p->pFd, zStr, nStr, pCsr->iOffset+nRead); + } zStr[nStr] = '\0'; nRead += nStr; if( eEvent==OS_OPEN ){ int iFileid = get32bits(&pCsr->aBuf[4]); @@ -1033,32 +1050,50 @@ static int vlogColumn( sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i ){ - unsigned int val; VfslogCsr *pCsr = (VfslogCsr *)pCursor; assert( i<7 ); - val = get32bits(&pCsr->aBuf[4*i]); switch( i ){ case 0: { + unsigned int val = get32bits(&pCsr->aBuf[0]); sqlite3_result_text(ctx, vfslog_eventname(val), -1, SQLITE_STATIC); break; } case 1: { + unsigned int val = get32bits(&pCsr->aBuf[4]); char *zStr = pCsr->zTransient; if( val!=0 && val<(unsigned)pCsr->nFile ){ zStr = pCsr->azFile[val]; } sqlite3_result_text(ctx, zStr, -1, SQLITE_TRANSIENT); break; } - default: + case 2: { + unsigned int v1 = get32bits(&pCsr->aBuf[8]); + unsigned int v2 = get32bits(&pCsr->aBuf[12]); + sqlite3_result_int64( + ctx,(((sqlite3_int64)v1) << 32) + (sqlite3_int64)v2 + ); + break; + } + case 6: { + unsigned int v1 = get32bits(&pCsr->aBuf[28]); + unsigned int v2 = get32bits(&pCsr->aBuf[32]); + sqlite3_result_int64( + ctx,(((sqlite3_int64)v1) << 32) + (sqlite3_int64)v2 + ); + break; + } + default: { + unsigned int val = get32bits(&pCsr->aBuf[4*(i+1)]); sqlite3_result_int(ctx, val); break; + } } return SQLITE_OK; } @@ -1178,15 +1213,16 @@ } zVfs = Tcl_GetString(objv[2]); zParent = Tcl_GetString(objv[3]); zLog = Tcl_GetString(objv[4]); if( *zParent=='\0' ) zParent = 0; - rc = sqlite3_vfslog_new(zVfs, zParent, zLog); + rc = sqlite3_vfslog_new(zVfs, zParent, zLog, 0); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, "failed", 0); return TCL_ERROR; } + sqlite3_vfs_register(sqlite3_vfs_find(zVfs), 1); break; }; case VL_REGISTER: { char *zDb; Index: tool/mksqlite3c.tcl ================================================================== --- tool/mksqlite3c.tcl +++ tool/mksqlite3c.tcl @@ -401,10 +401,12 @@ dbstat.c dbpage.c sqlite3session.c fts5.c stmt.c + + test_osinst.c } { copy_file tsrc/$file } # Synthesize an alternative sqlite3_sourceid() implementation that ADDED tool/osinst2sql.c Index: tool/osinst2sql.c ================================================================== --- /dev/null +++ tool/osinst2sql.c @@ -0,0 +1,58 @@ +/* +****************************************************************************** +*/ + +#include + +#include +#include + +int sqlite3_vfslog_register(sqlite3 *db); + +static int xCallback(void *pUnused, int nArg, char **azArg, char **azName){ + char *zPrint = 0; + + assert( nArg==7 ); + zPrint = sqlite3_mprintf( + "INSERT INTO osinst VALUES(%Q, %Q, %s, %s, %s, %s, %s);", + azArg[0], azArg[1], azArg[2], azArg[3], azArg[4], azArg[5], azArg[6] + ); + printf("%s\n", zPrint); + sqlite3_free(zPrint); + return SQLITE_OK; +} + +int main(int argc, char **argv){ + sqlite3 *db = 0; + int i; + + sqlite3_open("", &db); + sqlite3_vfslog_register(db); + + printf("BEGIN;\n"); + printf("CREATE TABLE IF NOT EXISTS osinst(\n"); + printf(" event TEXT, -- xOpen, xRead etc.\n"); + printf(" file TEXT, -- Name of file this call applies to\n"); + printf(" time INTEGER, -- Timestamp\n"); + printf(" clicks INTEGER, -- Time spent in call\n"); + printf(" rc INTEGER, -- Return value\n"); + printf(" size INTEGER, -- Bytes read or written\n"); + printf(" offset INTEGER -- File offset read or written\n"); + printf(");\n"); + + for(i=1; i