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 #ifdef SQLITE_ENABLE_INSTVFS 19 /* 20 ** C interface: 21 ** 22 ** sqlite3_instvfs_create() 23 ** sqlite3_instvfs_destroy() 24 ** sqlite3_instvfs_configure() 25 ** 26 ** sqlite3_instvfs_reset() 27 ** sqlite3_instvfs_get() 28 ** 29 ** sqlite3_instvfs_binarylog 30 ** sqlite3_instvfs_binarylog_marker 31 ** 32 ** Tcl interface (omitted if SQLITE_TEST is not set): 33 ** 34 ** sqlite3_instvfs create NAME ?PARENT? 35 ** 36 ** Create and register new vfs called $NAME, which is a wrapper around 37 ** the existing vfs $PARENT. If the PARENT argument is omitted, the 38 ** new vfs is a wrapper around the current default vfs. 39 ** 40 ** sqlite3_instvfs destroy NAME 41 ** 42 ** Deregister and destroy the vfs named $NAME, which must have been 43 ** created by an earlier invocation of [sqlite3_instvfs create]. 44 ** 45 ** sqlite3_instvfs configure NAME SCRIPT 46 ** 47 ** Configure the callback script for the vfs $NAME, which much have 48 ** been created by an earlier invocation of [sqlite3_instvfs create]. 49 ** After a callback script has been configured, it is invoked each 50 ** time a vfs or file method is called by SQLite. Before invoking 51 ** the callback script, five arguments are appended to it: 52 ** 53 ** * The name of the invoked method - i.e. "xRead". 54 ** 55 ** * The time consumed by the method call as measured by 56 ** sqlite3Hwtime() (an integer value) 57 ** 58 ** * A string value with a different meaning for different calls. 59 ** For file methods, the name of the file being operated on. For 60 ** other methods it is the filename argument, if any. 61 ** 62 ** * A 32-bit integer value with a call-specific meaning. 63 ** 64 ** * A 64-bit integer value. For xRead() and xWrite() calls this 65 ** is the file offset being written to or read from. Unused by 66 ** all other calls. 67 ** 68 ** sqlite3_instvfs reset NAME 69 ** 70 ** Zero the internal event counters associated with vfs $NAME, 71 ** which must have been created by an earlier invocation of 72 ** [sqlite3_instvfs create]. 73 ** 74 ** sqlite3_instvfs report NAME 75 ** 76 ** Return the values of the internal event counters associated 77 ** with vfs $NAME. The report format is a list with one element 78 ** for each method call (xWrite, xRead etc.). Each element is 79 ** itself a list with three elements: 80 ** 81 ** * The name of the method call - i.e. "xWrite", 82 ** * The total number of calls to the method (an integer). 83 ** * The aggregate time consumed by all calls to the method as 84 ** measured by sqlite3Hwtime() (an integer). 85 */ 86 87 #include "sqlite3.h" 88 #include <string.h> 89 #include <assert.h> 90 91 /* 92 ** Maximum pathname length supported by the inst backend. 93 */ 94 #define INST_MAX_PATHNAME 512 95 96 97 /* File methods */ 98 /* Vfs methods */ 99 #define OS_ACCESS 1 100 #define OS_CHECKRESERVEDLOCK 2 101 #define OS_CLOSE 3 102 #define OS_CURRENTTIME 4 103 #define OS_DELETE 5 104 #define OS_DEVCHAR 6 105 #define OS_FILECONTROL 7 106 #define OS_FILESIZE 8 107 #define OS_FULLPATHNAME 9 108 #define OS_LOCK 11 109 #define OS_OPEN 12 110 #define OS_RANDOMNESS 13 111 #define OS_READ 14 112 #define OS_SECTORSIZE 15 113 #define OS_SLEEP 16 114 #define OS_SYNC 17 115 #define OS_TRUNCATE 18 116 #define OS_UNLOCK 19 117 #define OS_WRITE 20 118 119 #define OS_NUMEVENTS 21 120 121 #define BINARYLOG_STRING 30 122 #define BINARYLOG_MARKER 31 123 124 #define BINARYLOG_PREPARE_V2 64 125 #define BINARYLOG_STEP 65 126 #define BINARYLOG_FINALIZE 66 127 128 struct InstVfs { 129 sqlite3_vfs base; 130 sqlite3_vfs *pVfs; 131 132 void *pClient; 133 void (*xDel)(void *); 134 void (*xCall)(void *, int, int, sqlite3_int64, int, const char *, int, int, sqlite3_int64); 135 136 /* Counters */ 137 sqlite3_int64 aTime[OS_NUMEVENTS]; 138 int aCount[OS_NUMEVENTS]; 139 140 int iNextFileId; 141 }; 142 typedef struct InstVfs InstVfs; 143 144 #define REALVFS(p) (((InstVfs *)(p))->pVfs) 145 146 typedef struct inst_file inst_file; 147 struct inst_file { 148 sqlite3_file base; 149 sqlite3_file *pReal; 150 InstVfs *pInstVfs; 151 const char *zName; 152 int iFileId; /* File id number */ 153 int flags; 154 }; 155 156 /* 157 ** Method declarations for inst_file. 158 */ 159 static int instClose(sqlite3_file*); 160 static int instRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 161 static int instWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); 162 static int instTruncate(sqlite3_file*, sqlite3_int64 size); 163 static int instSync(sqlite3_file*, int flags); 164 static int instFileSize(sqlite3_file*, sqlite3_int64 *pSize); 165 static int instLock(sqlite3_file*, int); 166 static int instUnlock(sqlite3_file*, int); 167 static int instCheckReservedLock(sqlite3_file*, int *pResOut); 168 static int instFileControl(sqlite3_file*, int op, void *pArg); 169 static int instSectorSize(sqlite3_file*); 170 static int instDeviceCharacteristics(sqlite3_file*); 171 172 /* 173 ** Method declarations for inst_vfs. 174 */ 175 static int instOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); 176 static int instDelete(sqlite3_vfs*, const char *zName, int syncDir); 177 static int instAccess(sqlite3_vfs*, const char *zName, int flags, int *); 178 static int instFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); 179 static void *instDlOpen(sqlite3_vfs*, const char *zFilename); 180 static void instDlError(sqlite3_vfs*, int nByte, char *zErrMsg); 181 static void (*instDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); 182 static void instDlClose(sqlite3_vfs*, void*); 183 static int instRandomness(sqlite3_vfs*, int nByte, char *zOut); 184 static int instSleep(sqlite3_vfs*, int microseconds); 185 static int instCurrentTime(sqlite3_vfs*, double*); 186 187 static void binarylog_blob(sqlite3_vfs *, const char *, int, int); 188 189 static sqlite3_vfs inst_vfs = { 190 1, /* iVersion */ 191 sizeof(inst_file), /* szOsFile */ 192 INST_MAX_PATHNAME, /* mxPathname */ 193 0, /* pNext */ 194 0, /* zName */ 195 0, /* pAppData */ 196 instOpen, /* xOpen */ 197 instDelete, /* xDelete */ 198 instAccess, /* xAccess */ 199 instFullPathname, /* xFullPathname */ 200 instDlOpen, /* xDlOpen */ 201 instDlError, /* xDlError */ 202 instDlSym, /* xDlSym */ 203 instDlClose, /* xDlClose */ 204 instRandomness, /* xRandomness */ 205 instSleep, /* xSleep */ 206 instCurrentTime, /* xCurrentTime */ 207 }; 208 209 static sqlite3_io_methods inst_io_methods = { 210 1, /* iVersion */ 211 instClose, /* xClose */ 212 instRead, /* xRead */ 213 instWrite, /* xWrite */ 214 instTruncate, /* xTruncate */ 215 instSync, /* xSync */ 216 instFileSize, /* xFileSize */ 217 instLock, /* xLock */ 218 instUnlock, /* xUnlock */ 219 instCheckReservedLock, /* xCheckReservedLock */ 220 instFileControl, /* xFileControl */ 221 instSectorSize, /* xSectorSize */ 222 instDeviceCharacteristics /* xDeviceCharacteristics */ 223 }; 224 225 /* 226 ** hwtime.h contains inline assembler code for implementing 227 ** high-performance timing routines. 228 */ 229 #include "hwtime.h" 230 231 #define OS_TIME_IO(eEvent, A, B, Call) { \ 232 inst_file *p = (inst_file *)pFile; \ 233 InstVfs *pInstVfs = p->pInstVfs; \ 234 int rc; \ 235 sqlite_uint64 t = sqlite3Hwtime(); \ 236 rc = Call; \ 237 t = sqlite3Hwtime() - t; \ 238 pInstVfs->aTime[eEvent] += t; \ 239 pInstVfs->aCount[eEvent] += 1; \ 240 if( pInstVfs->xCall ){ \ 241 pInstVfs->xCall( \ 242 pInstVfs->pClient,eEvent,p->iFileId,t,rc,p->zName,p->flags,A,B \ 243 ); \ 244 } \ 245 return rc; \ 246 } 247 248 #define OS_TIME_VFS(eEvent, Z, flags, A, B, Call) { \ 249 InstVfs *pInstVfs = (InstVfs *)pVfs; \ 250 int rc; \ 251 sqlite_uint64 t = sqlite3Hwtime(); \ 252 rc = Call; \ 253 t = sqlite3Hwtime() - t; \ 254 pInstVfs->aTime[eEvent] += t; \ 255 pInstVfs->aCount[eEvent] += 1; \ 256 if( pInstVfs->xCall ){ \ 257 pInstVfs->xCall(pInstVfs->pClient,eEvent,0, t, rc, Z, flags, A, B); \ 258 } \ 259 return rc; \ 260 } 261 262 /* 263 ** Close an inst-file. 264 */ 265 static int instClose(sqlite3_file *pFile){ 266 OS_TIME_IO(OS_CLOSE, 0, 0, 267 (p->pReal->pMethods ? p->pReal->pMethods->xClose(p->pReal) : SQLITE_OK) 268 ); 269 } 270 271 /* 272 ** Read data from an inst-file. 273 */ 274 static int instRead( 275 sqlite3_file *pFile, 276 void *zBuf, 277 int iAmt, 278 sqlite_int64 iOfst 279 ){ 280 sqlite3_vfs *pVfs = (sqlite3_vfs *)(((inst_file *)pFile)->pInstVfs); 281 OS_TIME_IO(OS_READ, iAmt, (binarylog_blob(pVfs, zBuf, iAmt, 1), iOfst), 282 p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst) 283 ); 284 } 285 286 /* 287 ** Write data to an inst-file. 288 */ 289 static int instWrite( 290 sqlite3_file *pFile, 291 const void *z, 292 int iAmt, 293 sqlite_int64 iOfst 294 ){ 295 sqlite3_vfs *pVfs = (sqlite3_vfs *)(((inst_file *)pFile)->pInstVfs); 296 binarylog_blob(pVfs, z, iAmt, 1); 297 OS_TIME_IO(OS_WRITE, iAmt, iOfst, 298 p->pReal->pMethods->xWrite(p->pReal, z, iAmt, iOfst) 299 ); 300 } 301 302 /* 303 ** Truncate an inst-file. 304 */ 305 static int instTruncate(sqlite3_file *pFile, sqlite_int64 size){ 306 OS_TIME_IO(OS_TRUNCATE, 0, (int)size, 307 p->pReal->pMethods->xTruncate(p->pReal, size) 308 ); 309 } 310 311 /* 312 ** Sync an inst-file. 313 */ 314 static int instSync(sqlite3_file *pFile, int flags){ 315 OS_TIME_IO(OS_SYNC, flags, 0, p->pReal->pMethods->xSync(p->pReal, flags)); 316 } 317 318 /* 319 ** Return the current file-size of an inst-file. 320 */ 321 static int instFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ 322 OS_TIME_IO(OS_FILESIZE, (int)(*pSize), 0, 323 p->pReal->pMethods->xFileSize(p->pReal, pSize) 324 ); 325 } 326 327 /* 328 ** Lock an inst-file. 329 */ 330 static int instLock(sqlite3_file *pFile, int eLock){ 331 OS_TIME_IO(OS_LOCK, eLock, 0, p->pReal->pMethods->xLock(p->pReal, eLock)); 332 } 333 334 /* 335 ** Unlock an inst-file. 336 */ 337 static int instUnlock(sqlite3_file *pFile, int eLock){ 338 OS_TIME_IO(OS_UNLOCK, eLock, 0, p->pReal->pMethods->xUnlock(p->pReal, eLock)); 339 } 340 341 /* 342 ** Check if another file-handle holds a RESERVED lock on an inst-file. 343 */ 344 static int instCheckReservedLock(sqlite3_file *pFile, int *pResOut){ 345 OS_TIME_IO(OS_CHECKRESERVEDLOCK, 0, 0, 346 p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut) 347 ); 348 } 349 350 /* 351 ** File control method. For custom operations on an inst-file. 352 */ 353 static int instFileControl(sqlite3_file *pFile, int op, void *pArg){ 354 OS_TIME_IO(OS_FILECONTROL, 0, 0, p->pReal->pMethods->xFileControl(p->pReal, op, pArg)); 355 } 356 357 /* 358 ** Return the sector-size in bytes for an inst-file. 359 */ 360 static int instSectorSize(sqlite3_file *pFile){ 361 OS_TIME_IO(OS_SECTORSIZE, 0, 0, p->pReal->pMethods->xSectorSize(p->pReal)); 362 } 363 364 /* 365 ** Return the device characteristic flags supported by an inst-file. 366 */ 367 static int instDeviceCharacteristics(sqlite3_file *pFile){ 368 OS_TIME_IO(OS_DEVCHAR, 0, 0, p->pReal->pMethods->xDeviceCharacteristics(p->pReal)); 369 } 370 371 /* 372 ** Open an inst file handle. 373 */ 374 static int instOpen( 375 sqlite3_vfs *pVfs, 376 const char *zName, 377 sqlite3_file *pFile, 378 int flags, 379 int *pOutFlags 380 ){ 381 inst_file *p = (inst_file *)pFile; 382 pFile->pMethods = &inst_io_methods; 383 p->pReal = (sqlite3_file *)&p[1]; 384 p->pInstVfs = (InstVfs *)pVfs; 385 p->zName = zName; 386 p->flags = flags; 387 p->iFileId = ++p->pInstVfs->iNextFileId; 388 389 binarylog_blob(pVfs, zName, -1, 0); 390 OS_TIME_VFS(OS_OPEN, zName, flags, p->iFileId, 0, 391 REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, p->pReal, flags, pOutFlags) 392 ); 393 } 394 395 /* 396 ** Delete the file located at zPath. If the dirSync argument is true, 397 ** ensure the file-system modifications are synced to disk before 398 ** returning. 399 */ 400 static int instDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 401 binarylog_blob(pVfs, zPath, -1, 0); 402 OS_TIME_VFS(OS_DELETE, zPath, 0, dirSync, 0, 403 REALVFS(pVfs)->xDelete(REALVFS(pVfs), zPath, dirSync) 404 ); 405 } 406 407 /* 408 ** Test for access permissions. Return true if the requested permission 409 ** is available, or false otherwise. 410 */ 411 static int instAccess( 412 sqlite3_vfs *pVfs, 413 const char *zPath, 414 int flags, 415 int *pResOut 416 ){ 417 binarylog_blob(pVfs, zPath, -1, 0); 418 OS_TIME_VFS(OS_ACCESS, zPath, 0, flags, *pResOut, 419 REALVFS(pVfs)->xAccess(REALVFS(pVfs), zPath, flags, pResOut) 420 ); 421 } 422 423 /* 424 ** Populate buffer zOut with the full canonical pathname corresponding 425 ** to the pathname in zPath. zOut is guaranteed to point to a buffer 426 ** of at least (INST_MAX_PATHNAME+1) bytes. 427 */ 428 static int instFullPathname( 429 sqlite3_vfs *pVfs, 430 const char *zPath, 431 int nOut, 432 char *zOut 433 ){ 434 OS_TIME_VFS( OS_FULLPATHNAME, zPath, 0, 0, 0, 435 REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zPath, nOut, zOut); 436 ); 437 } 438 439 /* 440 ** Open the dynamic library located at zPath and return a handle. 441 */ 442 static void *instDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 443 return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zPath); 444 } 445 446 /* 447 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable 448 ** utf-8 string describing the most recent error encountered associated 449 ** with dynamic libraries. 450 */ 451 static void instDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ 452 REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg); 453 } 454 455 /* 456 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle. 457 */ 458 static void (*instDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ 459 return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSym); 460 } 461 462 /* 463 ** Close the dynamic library handle pHandle. 464 */ 465 static void instDlClose(sqlite3_vfs *pVfs, void *pHandle){ 466 REALVFS(pVfs)->xDlClose(REALVFS(pVfs), pHandle); 467 } 468 469 /* 470 ** Populate the buffer pointed to by zBufOut with nByte bytes of 471 ** random data. 472 */ 473 static int instRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 474 OS_TIME_VFS( OS_RANDOMNESS, 0, 0, nByte, 0, 475 REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zBufOut); 476 ); 477 } 478 479 /* 480 ** Sleep for nMicro microseconds. Return the number of microseconds 481 ** actually slept. 482 */ 483 static int instSleep(sqlite3_vfs *pVfs, int nMicro){ 484 OS_TIME_VFS( OS_SLEEP, 0, 0, nMicro, 0, 485 REALVFS(pVfs)->xSleep(REALVFS(pVfs), nMicro) 486 ); 487 } 488 489 /* 490 ** Return the current time as a Julian Day number in *pTimeOut. 491 */ 492 static int instCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 493 OS_TIME_VFS( OS_CURRENTTIME, 0, 0, 0, 0, 494 REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pTimeOut) 495 ); 496 } 497 498 sqlite3_vfs *sqlite3_instvfs_create(const char *zName, const char *zParent){ 499 int nByte; 500 InstVfs *p; 501 sqlite3_vfs *pParent; 502 503 pParent = sqlite3_vfs_find(zParent); 504 if( !pParent ){ 505 return 0; 506 } 507 508 nByte = strlen(zName) + 1 + sizeof(InstVfs); 509 p = (InstVfs *)sqlite3_malloc(nByte); 510 if( p ){ 511 char *zCopy = (char *)&p[1]; 512 memset(p, 0, nByte); 513 memcpy(p, &inst_vfs, sizeof(sqlite3_vfs)); 514 p->pVfs = pParent; 515 memcpy(zCopy, zName, strlen(zName)); 516 p->base.zName = (const char *)zCopy; 517 p->base.szOsFile += pParent->szOsFile; 518 sqlite3_vfs_register((sqlite3_vfs *)p, 0); 519 } 520 521 return (sqlite3_vfs *)p; 522 } 523 524 void sqlite3_instvfs_configure( 525 sqlite3_vfs *pVfs, 526 void (*xCall)( 527 void*, 528 int, /* File id */ 529 int, /* Event code */ 530 sqlite3_int64, 531 int, /* Return code */ 532 const char*, /* File name */ 533 int, 534 int, 535 sqlite3_int64 536 ), 537 void *pClient, 538 void (*xDel)(void *) 539 ){ 540 InstVfs *p = (InstVfs *)pVfs; 541 assert( pVfs->xOpen==instOpen ); 542 if( p->xDel ){ 543 p->xDel(p->pClient); 544 } 545 p->xCall = xCall; 546 p->xDel = xDel; 547 p->pClient = pClient; 548 } 549 550 void sqlite3_instvfs_destroy(sqlite3_vfs *pVfs){ 551 if( pVfs ){ 552 sqlite3_vfs_unregister(pVfs); 553 sqlite3_instvfs_configure(pVfs, 0, 0, 0); 554 sqlite3_free(pVfs); 555 } 556 } 557 558 void sqlite3_instvfs_reset(sqlite3_vfs *pVfs){ 559 InstVfs *p = (InstVfs *)pVfs; 560 assert( pVfs->xOpen==instOpen ); 561 memset(p->aTime, 0, sizeof(sqlite3_int64)*OS_NUMEVENTS); 562 memset(p->aCount, 0, sizeof(int)*OS_NUMEVENTS); 563 } 564 565 const char *sqlite3_instvfs_name(int eEvent){ 566 const char *zEvent = 0; 567 568 switch( eEvent ){ 569 case OS_CLOSE: zEvent = "xClose"; break; 570 case OS_READ: zEvent = "xRead"; break; 571 case OS_WRITE: zEvent = "xWrite"; break; 572 case OS_TRUNCATE: zEvent = "xTruncate"; break; 573 case OS_SYNC: zEvent = "xSync"; break; 574 case OS_FILESIZE: zEvent = "xFilesize"; break; 575 case OS_LOCK: zEvent = "xLock"; break; 576 case OS_UNLOCK: zEvent = "xUnlock"; break; 577 case OS_CHECKRESERVEDLOCK: zEvent = "xCheckReservedLock"; break; 578 case OS_FILECONTROL: zEvent = "xFileControl"; break; 579 case OS_SECTORSIZE: zEvent = "xSectorSize"; break; 580 case OS_DEVCHAR: zEvent = "xDeviceCharacteristics"; break; 581 case OS_OPEN: zEvent = "xOpen"; break; 582 case OS_DELETE: zEvent = "xDelete"; break; 583 case OS_ACCESS: zEvent = "xAccess"; break; 584 case OS_FULLPATHNAME: zEvent = "xFullPathname"; break; 585 case OS_RANDOMNESS: zEvent = "xRandomness"; break; 586 case OS_SLEEP: zEvent = "xSleep"; break; 587 case OS_CURRENTTIME: zEvent = "xCurrentTime"; break; 588 } 589 590 return zEvent; 591 } 592 593 void sqlite3_instvfs_get( 594 sqlite3_vfs *pVfs, 595 int eEvent, 596 const char **pzEvent, 597 sqlite3_int64 *pnClick, 598 int *pnCall 599 ){ 600 InstVfs *p = (InstVfs *)pVfs; 601 assert( pVfs->xOpen==instOpen ); 602 if( eEvent<1 || eEvent>=OS_NUMEVENTS ){ 603 *pzEvent = 0; 604 *pnClick = 0; 605 *pnCall = 0; 606 return; 607 } 608 609 *pzEvent = sqlite3_instvfs_name(eEvent); 610 *pnClick = p->aTime[eEvent]; 611 *pnCall = p->aCount[eEvent]; 612 } 613 614 #define BINARYLOG_BUFFERSIZE 8192 615 616 struct InstVfsBinaryLog { 617 int nBuf; 618 char *zBuf; 619 sqlite3_int64 iOffset; 620 int log_data; 621 sqlite3_file *pOut; 622 char *zOut; /* Log file name */ 623 }; 624 typedef struct InstVfsBinaryLog InstVfsBinaryLog; 625 626 static void put32bits(unsigned char *p, unsigned int v){ 627 p[0] = v>>24; 628 p[1] = v>>16; 629 p[2] = v>>8; 630 p[3] = v; 631 } 632 633 static void binarylog_flush(InstVfsBinaryLog *pLog){ 634 sqlite3_file *pFile = pLog->pOut; 635 636 #ifdef SQLITE_TEST 637 extern int sqlite3_io_error_pending; 638 extern int sqlite3_io_error_persist; 639 extern int sqlite3_diskfull_pending; 640 641 int pending = sqlite3_io_error_pending; 642 int persist = sqlite3_io_error_persist; 643 int diskfull = sqlite3_diskfull_pending; 644 645 sqlite3_io_error_pending = 0; 646 sqlite3_io_error_persist = 0; 647 sqlite3_diskfull_pending = 0; 648 #endif 649 650 pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset); 651 pLog->iOffset += pLog->nBuf; 652 pLog->nBuf = 0; 653 654 #ifdef SQLITE_TEST 655 sqlite3_io_error_pending = pending; 656 sqlite3_io_error_persist = persist; 657 sqlite3_diskfull_pending = diskfull; 658 #endif 659 } 660 661 static void binarylog_xcall( 662 void *p, 663 int eEvent, 664 int iFileId, 665 sqlite3_int64 nClick, 666 int return_code, 667 const char *zName, 668 int flags, 669 int nByte, 670 sqlite3_int64 iOffset 671 ){ 672 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p; 673 unsigned char *zRec; 674 if( (28+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){ 675 binarylog_flush(pLog); 676 } 677 zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf]; 678 put32bits(&zRec[0], eEvent); 679 put32bits(&zRec[4], (int)iFileId); 680 put32bits(&zRec[8], (int)nClick); 681 put32bits(&zRec[12], return_code); 682 put32bits(&zRec[16], flags); 683 put32bits(&zRec[20], nByte); 684 put32bits(&zRec[24], (int)iOffset); 685 pLog->nBuf += 28; 686 } 687 688 static void binarylog_xdel(void *p){ 689 /* Close the log file and free the memory allocated for the 690 ** InstVfsBinaryLog structure. 691 */ 692 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p; 693 sqlite3_file *pFile = pLog->pOut; 694 if( pLog->nBuf ){ 695 binarylog_flush(pLog); 696 } 697 pFile->pMethods->xClose(pFile); 698 sqlite3_free(pLog->pOut); 699 sqlite3_free(pLog->zBuf); 700 sqlite3_free(pLog); 701 } 702 703 static void binarylog_blob( 704 sqlite3_vfs *pVfs, 705 const char *zBlob, 706 int nBlob, 707 int isBinary 708 ){ 709 InstVfsBinaryLog *pLog; 710 InstVfs *pInstVfs = (InstVfs *)pVfs; 711 712 if( pVfs->xOpen!=instOpen || pInstVfs->xCall!=binarylog_xcall ){ 713 return; 714 } 715 pLog = (InstVfsBinaryLog *)pInstVfs->pClient; 716 if( zBlob && (!isBinary || pLog->log_data) ){ 717 unsigned char *zRec; 718 int nWrite; 719 720 if( nBlob<0 ){ 721 nBlob = strlen(zBlob); 722 } 723 nWrite = nBlob + 28; 724 725 if( (nWrite+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){ 726 binarylog_flush(pLog); 727 } 728 729 zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf]; 730 memset(zRec, 0, nWrite); 731 put32bits(&zRec[0], BINARYLOG_STRING); 732 put32bits(&zRec[4], (int)nBlob); 733 put32bits(&zRec[8], (int)isBinary); 734 memcpy(&zRec[28], zBlob, nBlob); 735 pLog->nBuf += nWrite; 736 } 737 } 738 739 void sqlite3_instvfs_binarylog_call( 740 sqlite3_vfs *pVfs, 741 int eEvent, 742 sqlite3_int64 nClick, 743 int return_code, 744 const char *zString 745 ){ 746 InstVfs *pInstVfs = (InstVfs *)pVfs; 747 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)pInstVfs->pClient; 748 749 if( zString ){ 750 binarylog_blob(pVfs, zString, -1, 0); 751 } 752 binarylog_xcall(pLog, eEvent, 0, nClick, return_code, 0, 0, 0, 0); 753 } 754 755 void sqlite3_instvfs_binarylog_marker( 756 sqlite3_vfs *pVfs, 757 const char *zMarker 758 ){ 759 InstVfs *pInstVfs = (InstVfs *)pVfs; 760 InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)pInstVfs->pClient; 761 binarylog_blob(pVfs, zMarker, -1, 0); 762 binarylog_xcall(pLog, BINARYLOG_MARKER, 0, 0, 0, 0, 0, 0, 0); 763 } 764 765 sqlite3_vfs *sqlite3_instvfs_binarylog( 766 const char *zVfs, 767 const char *zParentVfs, 768 const char *zLog, 769 int log_data 770 ){ 771 InstVfsBinaryLog *p; 772 sqlite3_vfs *pVfs; 773 sqlite3_vfs *pParent; 774 int nByte; 775 int flags; 776 int rc; 777 778 pParent = sqlite3_vfs_find(zParentVfs); 779 if( !pParent ){ 780 return 0; 781 } 782 783 nByte = sizeof(InstVfsBinaryLog) + pParent->mxPathname+1; 784 p = (InstVfsBinaryLog *)sqlite3_malloc(nByte); 785 memset(p, 0, nByte); 786 p->zBuf = sqlite3_malloc(BINARYLOG_BUFFERSIZE); 787 p->zOut = (char *)&p[1]; 788 p->pOut = (sqlite3_file *)sqlite3_malloc(pParent->szOsFile); 789 p->log_data = log_data; 790 pParent->xFullPathname(pParent, zLog, pParent->mxPathname, p->zOut); 791 flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_MASTER_JOURNAL; 792 pParent->xDelete(pParent, p->zOut, 0); 793 rc = pParent->xOpen(pParent, p->zOut, p->pOut, flags, &flags); 794 if( rc==SQLITE_OK ){ 795 memcpy(p->zBuf, "sqlite_ostrace1.....", 20); 796 p->iOffset = 0; 797 p->nBuf = 20; 798 } 799 if( rc ){ 800 binarylog_xdel(p); 801 return 0; 802 } 803 804 pVfs = sqlite3_instvfs_create(zVfs, zParentVfs); 805 if( pVfs ){ 806 sqlite3_instvfs_configure(pVfs, binarylog_xcall, p, binarylog_xdel); 807 } 808 809 return pVfs; 810 } 811 #endif /* SQLITE_ENABLE_INSTVFS */ 812 813 /************************************************************************** 814 *************************************************************************** 815 ** Tcl interface starts here. 816 */ 817 #if SQLITE_TEST 818 819 #include <tcl.h> 820 821 #ifdef SQLITE_ENABLE_INSTVFS 822 struct InstVfsCall { 823 Tcl_Interp *interp; 824 Tcl_Obj *pScript; 825 }; 826 typedef struct InstVfsCall InstVfsCall; 827 828 static void test_instvfs_xcall( 829 void *p, 830 int eEvent, 831 int iFileId, 832 sqlite3_int64 nClick, 833 int return_code, 834 const char *zName, 835 int flags, 836 int nByte, 837 sqlite3_int64 iOffset 838 ){ 839 int rc; 840 InstVfsCall *pCall = (InstVfsCall *)p; 841 Tcl_Obj *pObj = Tcl_DuplicateObj( pCall->pScript); 842 const char *zEvent = sqlite3_instvfs_name(eEvent); 843 844 Tcl_IncrRefCount(pObj); 845 Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zEvent, -1)); 846 Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(nClick)); 847 Tcl_ListObjAppendElement(0, pObj, Tcl_NewStringObj(zName, -1)); 848 Tcl_ListObjAppendElement(0, pObj, Tcl_NewIntObj(nByte)); 849 Tcl_ListObjAppendElement(0, pObj, Tcl_NewWideIntObj(iOffset)); 850 851 rc = Tcl_EvalObjEx(pCall->interp, pObj, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); 852 if( rc ){ 853 Tcl_BackgroundError(pCall->interp); 854 } 855 Tcl_DecrRefCount(pObj); 856 } 857 858 static void test_instvfs_xdel(void *p){ 859 InstVfsCall *pCall = (InstVfsCall *)p; 860 Tcl_DecrRefCount(pCall->pScript); 861 sqlite3_free(pCall); 862 } 863 864 static int test_sqlite3_instvfs( 865 void * clientData, 866 Tcl_Interp *interp, 867 int objc, 868 Tcl_Obj *CONST objv[] 869 ){ 870 static const char *IV_strs[] = 871 { "create", "destroy", "reset", "report", "configure", "binarylog", "marker", 0 }; 872 enum IV_enum { IV_CREATE, IV_DESTROY, IV_RESET, IV_REPORT, IV_CONFIGURE, IV_BINARYLOG, IV_MARKER }; 873 int iSub; 874 875 if( objc<2 ){ 876 Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ..."); 877 } 878 if( Tcl_GetIndexFromObj(interp, objv[1], IV_strs, "sub-command", 0, &iSub) ){ 879 return TCL_ERROR; 880 } 881 882 switch( (enum IV_enum)iSub ){ 883 case IV_CREATE: { 884 char *zParent = 0; 885 sqlite3_vfs *p; 886 int isDefault = 0; 887 if( objc>2 && 0==strcmp("-default", Tcl_GetString(objv[2])) ){ 888 isDefault = 1; 889 } 890 if( (objc-isDefault)!=4 && (objc-isDefault)!=3 ){ 891 Tcl_WrongNumArgs(interp, 2, objv, "?-default? NAME ?PARENT-VFS?"); 892 return TCL_ERROR; 893 } 894 if( objc==(4+isDefault) ){ 895 zParent = Tcl_GetString(objv[3+isDefault]); 896 } 897 p = sqlite3_instvfs_create(Tcl_GetString(objv[2+isDefault]), zParent); 898 if( !p ){ 899 Tcl_AppendResult(interp, "error creating vfs ", 0); 900 return TCL_ERROR; 901 } 902 if( isDefault ){ 903 sqlite3_vfs_register(p, 1); 904 } 905 Tcl_SetObjResult(interp, objv[2]); 906 break; 907 } 908 case IV_BINARYLOG: { 909 char *zName = 0; 910 char *zLog = 0; 911 char *zParent = 0; 912 sqlite3_vfs *p; 913 int isDefault = 0; 914 int isLogdata = 0; 915 int argbase = 2; 916 917 for(argbase=2; argbase<(objc-2); argbase++){ 918 if( 0==strcmp("-default", Tcl_GetString(objv[argbase])) ){ 919 isDefault = 1; 920 } 921 else if( 0==strcmp("-parent", Tcl_GetString(objv[argbase])) ){ 922 argbase++; 923 zParent = Tcl_GetString(objv[argbase]); 924 } 925 else if( 0==strcmp("-logdata", Tcl_GetString(objv[argbase])) ){ 926 isLogdata = 1; 927 }else{ 928 break; 929 } 930 } 931 932 if( (objc-argbase)!=2 ){ 933 Tcl_WrongNumArgs( 934 interp, 2, objv, "?-default? ?-parent VFS? ?-logdata? NAME LOGFILE" 935 ); 936 return TCL_ERROR; 937 } 938 zName = Tcl_GetString(objv[argbase]); 939 zLog = Tcl_GetString(objv[argbase+1]); 940 p = sqlite3_instvfs_binarylog(zName, zParent, zLog, isLogdata); 941 if( !p ){ 942 Tcl_AppendResult(interp, "error creating vfs ", 0); 943 return TCL_ERROR; 944 } 945 if( isDefault ){ 946 sqlite3_vfs_register(p, 1); 947 } 948 Tcl_SetObjResult(interp, objv[2]); 949 break; 950 } 951 952 case IV_MARKER: { 953 sqlite3_vfs *p; 954 if( objc!=4 ){ 955 Tcl_WrongNumArgs(interp, 2, objv, "VFS MARKER"); 956 return TCL_ERROR; 957 } 958 p = sqlite3_vfs_find(Tcl_GetString(objv[2])); 959 if( !p || p->xOpen!=instOpen ){ 960 Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); 961 return TCL_ERROR; 962 } 963 sqlite3_instvfs_binarylog_marker(p, Tcl_GetString(objv[3])); 964 Tcl_ResetResult(interp); 965 break; 966 } 967 968 case IV_CONFIGURE: { 969 InstVfsCall *pCall; 970 971 sqlite3_vfs *p; 972 if( objc!=4 ){ 973 Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 974 return TCL_ERROR; 975 } 976 p = sqlite3_vfs_find(Tcl_GetString(objv[2])); 977 if( !p || p->xOpen!=instOpen ){ 978 Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); 979 return TCL_ERROR; 980 } 981 982 if( strlen(Tcl_GetString(objv[3])) ){ 983 pCall = (InstVfsCall *)sqlite3_malloc(sizeof(InstVfsCall)); 984 pCall->interp = interp; 985 pCall->pScript = Tcl_DuplicateObj(objv[3]); 986 Tcl_IncrRefCount(pCall->pScript); 987 sqlite3_instvfs_configure(p, 988 test_instvfs_xcall, (void *)pCall, test_instvfs_xdel 989 ); 990 }else{ 991 sqlite3_instvfs_configure(p, 0, 0, 0); 992 } 993 break; 994 } 995 996 case IV_REPORT: 997 case IV_DESTROY: 998 case IV_RESET: { 999 sqlite3_vfs *p; 1000 if( objc!=3 ){ 1001 Tcl_WrongNumArgs(interp, 2, objv, "NAME"); 1002 return TCL_ERROR; 1003 } 1004 p = sqlite3_vfs_find(Tcl_GetString(objv[2])); 1005 if( !p || p->xOpen!=instOpen ){ 1006 Tcl_AppendResult(interp, "no such vfs: ", Tcl_GetString(objv[2]), 0); 1007 return TCL_ERROR; 1008 } 1009 1010 if( ((enum IV_enum)iSub)==IV_DESTROY ){ 1011 sqlite3_instvfs_destroy(p); 1012 } 1013 if( ((enum IV_enum)iSub)==IV_RESET ){ 1014 sqlite3_instvfs_reset(p); 1015 } 1016 if( ((enum IV_enum)iSub)==IV_REPORT ){ 1017 int ii; 1018 Tcl_Obj *pRet = Tcl_NewObj(); 1019 1020 const char *zName = (char *)1; 1021 sqlite3_int64 nClick; 1022 int nCall; 1023 for(ii=1; zName; ii++){ 1024 sqlite3_instvfs_get(p, ii, &zName, &nClick, &nCall); 1025 if( zName ){ 1026 Tcl_Obj *pElem = Tcl_NewObj(); 1027 Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zName, -1)); 1028 Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(nCall)); 1029 Tcl_ListObjAppendElement(0, pElem, Tcl_NewWideIntObj(nClick)); 1030 Tcl_ListObjAppendElement(0, pRet, pElem); 1031 } 1032 } 1033 1034 Tcl_SetObjResult(interp, pRet); 1035 } 1036 1037 break; 1038 } 1039 } 1040 1041 return TCL_OK; 1042 } 1043 #endif /* SQLITE_ENABLE_INSTVFS */ 1044 1045 /* Alternative implementation of sqlite3_instvfs when the real 1046 ** implementation is unavailable. 1047 */ 1048 #ifndef SQLITE_ENABLE_INSTVFS 1049 static int test_sqlite3_instvfs( 1050 void * clientData, 1051 Tcl_Interp *interp, 1052 int objc, 1053 Tcl_Obj *CONST objv[] 1054 ){ 1055 Tcl_AppendResult(interp, 1056 "not compiled with -DSQLITE_ENABLE_INSTVFS; sqlite3_instvfs is " 1057 "unavailable", (char*)0); 1058 return TCL_ERROR; 1059 } 1060 #endif /* !defined(SQLITE_ENABLE_INSTVFS) */ 1061 1062 int SqlitetestOsinst_Init(Tcl_Interp *interp){ 1063 Tcl_CreateObjCommand(interp, "sqlite3_instvfs", test_sqlite3_instvfs, 0, 0); 1064 return TCL_OK; 1065 } 1066 1067 #endif /* SQLITE_TEST */ 1068