diff options
| author | Wez Furlong <wez@php.net> | 2005-01-07 05:27:27 +0000 | 
|---|---|---|
| committer | Wez Furlong <wez@php.net> | 2005-01-07 05:27:27 +0000 | 
| commit | e6c282a76639fe4b6e9166210b4f338b83df44e7 (patch) | |
| tree | 6b0cb08f8b1efc397477efcfff0bbffaedbe0f36 /ext/pdo_sqlite/sqlite/src/os_test.c | |
| parent | 02d6b65c672835f27fd2b160338ab05f1dfca3a1 (diff) | |
| download | php-git-e6c282a76639fe4b6e9166210b4f338b83df44e7.tar.gz | |
jumbo commit; implement sqlstate error codes.
Bundle sqlite3
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/os_test.c')
| -rw-r--r-- | ext/pdo_sqlite/sqlite/src/os_test.c | 461 | 
1 files changed, 461 insertions, 0 deletions
| diff --git a/ext/pdo_sqlite/sqlite/src/os_test.c b/ext/pdo_sqlite/sqlite/src/os_test.c new file mode 100644 index 0000000000..0e292bc428 --- /dev/null +++ b/ext/pdo_sqlite/sqlite/src/os_test.c @@ -0,0 +1,461 @@ +/* +** 2004 May 22 +** +** The author disclaims copyright to this source code.  In place of +** a legal notice, here is a blessing: +** +**    May you do good and not evil. +**    May you find forgiveness for yourself and forgive others. +**    May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains code that is specific to Unix systems. It is used +** for testing SQLite only. +*/ +#if OS_TEST              /* This file is used for the test backend only */ +#include "sqliteInt.h" +#include "os.h"          /* Must be first to enable large file support */ + +#define sqlite3OsOpenReadWrite     sqlite3RealOpenReadWrite +#define sqlite3OsOpenExclusive     sqlite3RealOpenExclusive +#define sqlite3OsOpenReadOnly      sqlite3RealOpenReadOnly +#define sqlite3OsOpenDirectory     sqlite3RealOpenDirectory +#define sqlite3OsClose             sqlite3RealClose +#define sqlite3OsRead              sqlite3RealRead +#define sqlite3OsWrite             sqlite3RealWrite +#define sqlite3OsSeek              sqlite3RealSeek +#define sqlite3OsSync              sqlite3RealSync +#define sqlite3OsTruncate          sqlite3RealTruncate +#define sqlite3OsFileSize          sqlite3RealFileSize +#define sqlite3OsLock              sqlite3RealLock +#define sqlite3OsUnlock            sqlite3RealUnlock +#define sqlite3OsCheckReservedLock sqlite3RealCheckReservedLock + +#define OsFile OsRealFile +#define OS_UNIX 1 +#include "os_unix.c" +#undef OS_UNIX +#undef OsFile + +#undef sqlite3OsOpenReadWrite      +#undef sqlite3OsOpenExclusive      +#undef sqlite3OsOpenReadOnly       +#undef sqlite3OsOpenDirectory      +#undef sqlite3OsClose              +#undef sqlite3OsRead               +#undef sqlite3OsWrite              +#undef sqlite3OsSeek               +#undef sqlite3OsSync               +#undef sqlite3OsTruncate           +#undef sqlite3OsFileSize           +#undef sqlite3OsLock               +#undef sqlite3OsUnlock             +#undef sqlite3OsCheckReservedLock  + +#define BLOCKSIZE 512 +#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE) + + +/* +** The following variables control when a simulated crash occurs. +** +** If iCrashDelay is non-zero, then zCrashFile contains (full path) name of +** a file that SQLite will call sqlite3OsSync() on. Each time this happens +** iCrashDelay is decremented. If iCrashDelay is zero after being +** decremented, a "crash" occurs during the sync() operation. +** +** In other words, a crash occurs the iCrashDelay'th time zCrashFile is +** synced. +*/ +static int iCrashDelay = 0; +char zCrashFile[256]; + +/* +** Set the value of the two crash parameters. +*/ +void sqlite3SetCrashParams(int iDelay, char const *zFile){ +  sqlite3OsEnterMutex(); +  assert( strlen(zFile)<256 ); +  strcpy(zCrashFile, zFile); +  iCrashDelay = iDelay; +  sqlite3OsLeaveMutex(); +} + +/* +** File zPath is being sync()ed. Return non-zero if this should +** cause a crash. +*/ +static int crashRequired(char const *zPath){ +  int r; +  int n; +  sqlite3OsEnterMutex(); +  n = strlen(zCrashFile); +  if( zCrashFile[n-1]=='*' ){ +    n--; +  }else if( strlen(zPath)>n ){ +    n = strlen(zPath); +  } +  r = 0; +  if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){ +    iCrashDelay--; +    if( iCrashDelay<=0 ){ +      r = 1; +    } +  } +  sqlite3OsLeaveMutex(); +  return r; +} + + +static OsTestFile *pAllFiles = 0; + +/* +** Initialise the os_test.c specific fields of pFile. +*/ +static void initFile(OsFile *id, char const *zName){ +  OsTestFile *pFile = (OsTestFile *) +      sqliteMalloc(sizeof(OsTestFile) + strlen(zName)+1); +  pFile->nMaxWrite = 0;  +  pFile->nBlk = 0;  +  pFile->apBlk = 0;  +  pFile->zName = (char *)(&pFile[1]); +  strcpy(pFile->zName, zName); +  *id = pFile; +  pFile->pNext = pAllFiles; +  pAllFiles = pFile; +} + +/* +** Undo the work done by initFile. Delete the OsTestFile structure +** and unlink the structure from the pAllFiles list. +*/ +static void closeFile(OsFile *id){ +  OsTestFile *pFile = *id; +  if( pFile==pAllFiles ){ +    pAllFiles = pFile->pNext; +  }else{ +    OsTestFile *p; +    for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){ +      assert( p ); +    } +    p->pNext = pFile->pNext; +  } +  sqliteFree(pFile); +  *id = 0; +} + +/* +** Return the current seek offset from the start of the file. This +** is unix-only code. +*/ +static i64 osTell(OsTestFile *pFile){ +  return lseek(pFile->fd.h, 0, SEEK_CUR); +} + +/* +** Load block 'blk' into the cache of pFile. +*/ +static int cacheBlock(OsTestFile *pFile, int blk){ +  if( blk>=pFile->nBlk ){ +    int n = ((pFile->nBlk * 2) + 100 + blk); +    /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */ +    pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*)); +    if( !pFile->apBlk ) return SQLITE_NOMEM; +    memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*)); +    pFile->nBlk = n; +  } + +  if( !pFile->apBlk[blk] ){ +    i64 filesize; +    int rc; + +    u8 *p = sqliteMalloc(BLOCKSIZE); +    if( !p ) return SQLITE_NOMEM; +    pFile->apBlk[blk] = p; + +    rc = sqlite3RealFileSize(&pFile->fd, &filesize); +    if( rc!=SQLITE_OK ) return rc; + +    if( BLOCK_OFFSET(blk)<filesize ){ +      int len = BLOCKSIZE; +      rc = sqlite3RealSeek(&pFile->fd, blk*BLOCKSIZE); +      if( BLOCK_OFFSET(blk+1)>filesize ){ +        len = filesize - BLOCK_OFFSET(blk); +      } +      if( rc!=SQLITE_OK ) return rc; +      rc = sqlite3RealRead(&pFile->fd, p, len); +      if( rc!=SQLITE_OK ) return rc; +    } +  } + +  return SQLITE_OK; +} + +/* #define TRACE_WRITECACHE */ + +/* +** Write the cache of pFile to disk. If crash is non-zero, randomly +** skip blocks when writing. The cache is deleted before returning. +*/ +static int writeCache2(OsTestFile *pFile, int crash){ +  int i; +  int nMax = pFile->nMaxWrite; +  i64 offset; +  int rc = SQLITE_OK; + +  offset = osTell(pFile); +  for(i=0; i<pFile->nBlk; i++){ +    u8 *p = pFile->apBlk[i]; +    if( p ){ +      int skip = 0; +      int trash = 0; +      if( crash ){ +        char random; +        sqlite3Randomness(1, &random); +        if( random & 0x01 ){ +          if( random & 0x02 ){ +            trash = 1; +#ifdef TRACE_WRITECACHE +printf("Trashing block %d of %s\n", i, pFile->zName);  +#endif +          }else{ +            skip = 1; +#ifdef TRACE_WRITECACHE +printf("Skiping block %d of %s\n", i, pFile->zName);  +#endif +          } +        }else{ +#ifdef TRACE_WRITECACHE +printf("Writing block %d of %s\n", i, pFile->zName);  +#endif +        } +      } +      if( rc==SQLITE_OK ){ +        rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i)); +      } +      if( rc==SQLITE_OK && !skip ){ +        int len = BLOCKSIZE; +        if( BLOCK_OFFSET(i+1)>nMax ){ +          len = nMax-BLOCK_OFFSET(i); +        } +        if( trash ){ +          sqlite3Randomness(len, p); +        } +        rc = sqlite3RealWrite(&pFile->fd, p, len); +      } +      sqliteFree(p); +    } +  } +  sqliteFree(pFile->apBlk); +  pFile->nBlk = 0; +  pFile->apBlk = 0; +  pFile->nMaxWrite = 0; + +  if( rc==SQLITE_OK ){ +    rc = sqlite3RealSeek(&pFile->fd, offset); +  } +  return rc; +} + +/* +** Write the cache to disk. +*/ +static int writeCache(OsTestFile *pFile){ +  if( pFile->apBlk ){ +    int c = crashRequired(pFile->zName); +    if( c ){ +      OsTestFile *p; +#ifdef TRACE_WRITECACHE +      printf("\nCrash during sync of %s\n", pFile->zName); +#endif +      for(p=pAllFiles; p; p=p->pNext){ +        writeCache2(p, 1); +      } +      exit(-1); +    }else{ +      return writeCache2(pFile, 0); +    } +  } +  return SQLITE_OK; +} + +/* +** Close the file. +*/ +int sqlite3OsClose(OsFile *id){ +  if( !(*id) ) return SQLITE_OK; +  if( (*id)->fd.isOpen ){ +    /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ +    writeCache(*id); +    sqlite3RealClose(&(*id)->fd); +  } +  closeFile(id); +  return SQLITE_OK; +} + +int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ +  i64 offset;       /* The current offset from the start of the file */ +  i64 end;          /* The byte just past the last byte read */ +  int blk;            /* Block number the read starts on */ +  int i; +  u8 *zCsr; +  int rc = SQLITE_OK; +  OsTestFile *pFile = *id; + +  offset = osTell(pFile); +  end = offset+amt; +  blk = (offset/BLOCKSIZE); + +  zCsr = (u8 *)pBuf; +  for(i=blk; i*BLOCKSIZE<end; i++){ +    int off = 0; +    int len = 0; + + +    if( BLOCK_OFFSET(i) < offset ){ +      off = offset-BLOCK_OFFSET(i); +    } +    len = BLOCKSIZE - off; +    if( BLOCK_OFFSET(i+1) > end ){ +      len = len - (BLOCK_OFFSET(i+1)-end); +    } + +    if( i<pFile->nBlk && pFile->apBlk[i]){ +      u8 *pBlk = pFile->apBlk[i]; +      memcpy(zCsr, &pBlk[off], len); +    }else{ +      rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i) + off); +      if( rc!=SQLITE_OK ) return rc; +      rc = sqlite3RealRead(&pFile->fd, zCsr, len); +      if( rc!=SQLITE_OK ) return rc; +    } + +    zCsr += len; +  } +  assert( zCsr==&((u8 *)pBuf)[amt] ); + +  rc = sqlite3RealSeek(&pFile->fd, end); +  return rc; +} + +int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ +  i64 offset;       /* The current offset from the start of the file */ +  i64 end;          /* The byte just past the last byte written */ +  int blk;            /* Block number the write starts on */ +  int i; +  const u8 *zCsr; +  int rc = SQLITE_OK; +  OsTestFile *pFile = *id; + +  offset = osTell(pFile); +  end = offset+amt; +  blk = (offset/BLOCKSIZE); + +  zCsr = (u8 *)pBuf; +  for(i=blk; i*BLOCKSIZE<end; i++){ +    u8 *pBlk; +    int off = 0; +    int len = 0; + +    /* Make sure the block is in the cache */ +    rc = cacheBlock(pFile, i); +    if( rc!=SQLITE_OK ) return rc; + +    /* Write into the cache */ +    pBlk = pFile->apBlk[i]; +    assert( pBlk ); + +    if( BLOCK_OFFSET(i) < offset ){ +      off = offset-BLOCK_OFFSET(i); +    } +    len = BLOCKSIZE - off; +    if( BLOCK_OFFSET(i+1) > end ){ +      len = len - (BLOCK_OFFSET(i+1)-end); +    } +    memcpy(&pBlk[off], zCsr, len); +    zCsr += len; +  } +  if( pFile->nMaxWrite<end ){ +    pFile->nMaxWrite = end; +  } +  assert( zCsr==&((u8 *)pBuf)[amt] ); + +  rc = sqlite3RealSeek(&pFile->fd, end); +  return rc; +} + +/* +** Sync the file. First flush the write-cache to disk, then call the +** real sync() function. +*/ +int sqlite3OsSync(OsFile *id){ +  int rc; +  /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ +  rc = writeCache(*id); +  if( rc!=SQLITE_OK ) return rc; +  rc = sqlite3RealSync(&(*id)->fd); +  return rc; +} + +/* +** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new +** file size to ensure that nothing in the write-cache past this point +** is written to disk. +*/ +int sqlite3OsTruncate(OsFile *id, i64 nByte){ +  (*id)->nMaxWrite = nByte; +  return sqlite3RealTruncate(&(*id)->fd, nByte); +} + +/* +** Return the size of the file. If the cache contains a write that extended +** the file, then return this size instead of the on-disk size. +*/ +int sqlite3OsFileSize(OsFile *id, i64 *pSize){ +  int rc = sqlite3RealFileSize(&(*id)->fd, pSize); +  if( rc==SQLITE_OK && pSize && *pSize<(*id)->nMaxWrite ){ +    *pSize = (*id)->nMaxWrite; +  } +  return rc; +} + +/* +** The three functions used to open files. All that is required is to +** initialise the os_test.c specific fields and then call the corresponding +** os_unix.c function to really open the file. +*/ +int sqlite3OsOpenReadWrite(const char *zFilename, OsFile *id, int *pReadonly){ +  initFile(id, zFilename); +  return sqlite3RealOpenReadWrite(zFilename, &(*id)->fd, pReadonly); +} +int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ +  initFile(id, zFilename); +  return sqlite3RealOpenExclusive(zFilename, &(*id)->fd, delFlag); +} +int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ +  initFile(id, zFilename); +  return sqlite3RealOpenReadOnly(zFilename, &(*id)->fd); +} + +/* +** These six function calls are passed straight through to the os_unix.c +** backend. +*/ +int sqlite3OsSeek(OsFile *id, i64 offset){ +  return sqlite3RealSeek(&(*id)->fd, offset); +} +int sqlite3OsCheckReservedLock(OsFile *id){ +  return sqlite3RealCheckReservedLock(&(*id)->fd); +} +int sqlite3OsLock(OsFile *id, int locktype){ +  return sqlite3RealLock(&(*id)->fd, locktype); +} +int sqlite3OsUnlock(OsFile *id, int locktype){ +  return sqlite3RealUnlock(&(*id)->fd, locktype); +} +int sqlite3OsOpenDirectory(const char *zDirname, OsFile *id){ +  return sqlite3RealOpenDirectory(zDirname, &(*id)->fd); +} + +#endif /* OS_TEST */ | 
