aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/os.h6
-rw-r--r--src/os_test.c384
-rw-r--r--src/os_test.h36
-rw-r--r--src/os_unix.c76
-rw-r--r--src/pager.c6
-rw-r--r--src/sqliteInt.h7
-rw-r--r--src/vdbeaux.c3
7 files changed, 474 insertions, 44 deletions
diff --git a/src/os.h b/src/os.h
index 225c2d862..fa61b6d98 100644
--- a/src/os.h
+++ b/src/os.h
@@ -23,7 +23,7 @@
** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix.
** The MacOS build is designed to use CodeWarrior (tested with v8)
*/
-#ifndef OS_UNIX
+#if !defined(OS_UNIX) && !defined(OS_TEST)
# ifndef OS_WIN
# ifndef OS_MAC
# if defined(__MACOS__)
@@ -57,6 +57,9 @@
/*
** Invoke the appropriate operating-system specific header file.
*/
+#if OS_TEST
+# include "os_test.h"
+#endif
#if OS_UNIX
# include "os_unix.h"
#endif
@@ -154,7 +157,6 @@
int sqlite3OsDelete(const char*);
int sqlite3OsFileExists(const char*);
-int sqliteOsFileRename(const char*, const char*);
int sqlite3OsOpenReadWrite(const char*, OsFile*, int*);
int sqlite3OsOpenExclusive(const char*, OsFile*, int);
int sqlite3OsOpenReadOnly(const char*, OsFile*);
diff --git a/src/os_test.c b/src/os_test.c
new file mode 100644
index 000000000..b6fd755f1
--- /dev/null
+++ b/src/os_test.c
@@ -0,0 +1,384 @@
+/*
+** 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.
+*/
+#include "os.h" /* Must be first to enable large file support */
+#if OS_TEST /* This file is used for the test backend only */
+#include "sqliteInt.h"
+
+#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 sqlite3OsFileModTime sqlite3RealFileModTime
+#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 sqlite3OsFileModTime
+#undef sqlite3OsLock
+#undef sqlite3OsUnlock
+#undef sqlite3OsCheckReservedLock
+
+#define BLOCKSIZE 512
+#define BLOCK_OFFSET(x) ((x) * BLOCKSIZE)
+
+
+/*
+** The crash-seed. Accessed via functions crashseed() and
+** sqlite3SetCrashseed().
+*/
+static int crashseed_var = 0;
+
+/*
+** This function is used to set the value of the 'crash-seed' integer.
+**
+** If the crash-seed is 0, the default value, then whenever sqlite3OsSync()
+** or sqlite3OsClose() is called, the write cache is written to disk before
+** the os_unix.c Sync() or Close() function is called.
+**
+** If the crash-seed is non-zero, then it is used to determine a subset of
+** the write-cache to actually write to disk before calling Sync() or
+** Close() in os_unix.c. The actual subset of writes selected is not
+** significant, except that it is constant for a given value of the
+** crash-seed and cache contents. Before returning, exit(-1) is invoked.
+*/
+void sqlite3SetCrashseed(int seed){
+ sqlite3OsEnterMutex();
+ crashseed_var = seed;
+ sqlite3OsLeaveMutex();
+}
+
+/*
+** Retrieve the current value of the crash-seed.
+*/
+static int crashseed(){
+ int i;
+ sqlite3OsEnterMutex();
+ i = crashseed_var;
+ sqlite3OsLeaveMutex();
+ return i;
+}
+
+/*
+** Initialise the os_test.c specific fields of pFile.
+*/
+static void initFile(OsFile *pFile){
+ pFile->nMaxWrite = 0;
+ pFile->nBlk = 0;
+ pFile->apBlk = 0;
+}
+
+/*
+** Return the current seek offset from the start of the file. This
+** is unix-only code.
+*/
+static off_t osTell(OsFile *pFile){
+ return lseek(pFile->fd.h, 0, SEEK_CUR);
+}
+
+/*
+** Load block 'blk' into the cache of pFile.
+*/
+static int cacheBlock(OsFile *pFile, int blk){
+ if( blk>=pFile->nBlk ){
+ int n = ((pFile->nBlk * 2) + 100 + blk);
+ pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*));
+ if( !pFile->apBlk ) return SQLITE_NOMEM;
+ pFile->nBlk = n;
+ }
+
+ if( !pFile->apBlk[blk] ){
+ off_t 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;
+}
+
+/*
+** 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(OsFile *pFile, int crash){
+ int i;
+ int nMax = pFile->nMaxWrite;
+ off_t 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;
+ if( crash ){
+ char random;
+ sqlite3Randomness(1, &random);
+ if( random & 0x01 ) skip = 1;
+ }
+
+ 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);
+ }
+ 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(OsFile *pFile){
+ if( crashseed() ){
+ /* FIX ME: writeCache2() should be called on all open files
+ ** here. */
+ writeCache2(pFile, 1);
+ exit(-1);
+ }else{
+ return writeCache2(pFile, 0);
+ }
+}
+
+/*
+** Close the file.
+*/
+int sqlite3OsClose(OsFile *id){
+ if( !id->fd.isOpen ) return SQLITE_OK;
+ writeCache(id);
+ sqlite3RealClose(&id->fd);
+ return SQLITE_OK;
+}
+
+int sqlite3OsRead(OsFile *id, void *pBuf, int amt){
+ off_t offset; /* The current offset from the start of the file */
+ off_t 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;
+
+ offset = osTell(id);
+ 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<id->nBlk && id->apBlk[i]){
+ u8 *pBlk = id->apBlk[i];
+ memcpy(zCsr, &pBlk[off], len);
+ }else{
+ rc = sqlite3RealSeek(&id->fd, BLOCK_OFFSET(i) + off);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = sqlite3RealRead(&id->fd, zCsr, len);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
+ zCsr += len;
+ }
+ assert( zCsr==&((u8 *)pBuf)[amt] );
+
+ rc = sqlite3RealSeek(&id->fd, end);
+ return rc;
+}
+
+int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
+ off_t offset; /* The current offset from the start of the file */
+ off_t 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;
+
+ offset = osTell(id);
+ 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(id, i);
+ if( rc!=SQLITE_OK ) return rc;
+
+ /* Write into the cache */
+ pBlk = id->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( id->nMaxWrite<end ){
+ id->nMaxWrite = end;
+ }
+ assert( zCsr==&((u8 *)pBuf)[amt] );
+
+ rc = sqlite3RealSeek(&id->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 = 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, off_t 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, off_t *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);
+ return sqlite3RealOpenReadWrite(zFilename, &id->fd, pReadonly);
+}
+int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
+ initFile(id);
+ return sqlite3RealOpenExclusive(zFilename, &id->fd, delFlag);
+}
+int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
+ initFile(id);
+ return sqlite3RealOpenReadOnly(zFilename, &id->fd);
+}
+
+/*
+** These six function calls are passed straight through to the os_unix.c
+** backend.
+*/
+int sqlite3OsSeek(OsFile *id, off_t 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 sqlite3OsFileModTime(OsFile *id, double *prNow){
+ return sqlite3RealFileModTime(&id->fd, prNow);
+}
+int sqlite3OsOpenDirectory(const char *zDirname, OsFile *id){
+ return sqlite3RealOpenDirectory(zDirname, &id->fd);
+}
+
+#endif /* OS_TEST */
diff --git a/src/os_test.h b/src/os_test.h
new file mode 100644
index 000000000..bf913eb5c
--- /dev/null
+++ b/src/os_test.h
@@ -0,0 +1,36 @@
+/*
+** 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.
+**
+******************************************************************************
+**
+*/
+#ifndef _SQLITE_OS_TEST_H_
+#define _SQLITE_OS_TEST_H_
+
+#define OsFile OsRealFile
+#define OS_UNIX 1
+#include "os_unix.h"
+#undef OS_UNIX
+#undef OsFile
+
+/* Include sqliteInt.h now to get the type u8. */
+#include "sqliteInt.h"
+
+typedef struct OsFile OsFile;
+struct OsFile {
+ u8 **apBlk; /* Array of blocks that have been written to. */
+ int nBlk; /* Size of apBlock. */
+ int nMaxWrite; /* Largest offset written to. */
+ OsRealFile fd;
+};
+
+void sqlite3SetCrashseed(int seed);
+
+#endif /* _SQLITE_OS_UNIX_H_ */
diff --git a/src/os_unix.c b/src/os_unix.c
index 8276c9e0b..e707835f1 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -513,44 +513,6 @@ int sqlite3OsTempFileName(char *zBuf){
}
/*
-** Close a file.
-*/
-int sqlite3OsClose(OsFile *id){
- if( !id->isOpen ) return SQLITE_OK;
- sqlite3OsUnlock(id, NO_LOCK);
- if( id->dirfd>=0 ) close(id->dirfd);
- id->dirfd = -1;
- sqlite3OsEnterMutex();
- if( id->pOpen->nLock ){
- /* If there are outstanding locks, do not actually close the file just
- ** yet because that would clear those locks. Instead, add the file
- ** descriptor to pOpen->aPending. It will be automatically closed when
- ** the last lock is cleared.
- */
- int *aNew;
- struct openCnt *pOpen = id->pOpen;
- pOpen->nPending++;
- aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
- if( aNew==0 ){
- /* If a malloc fails, just leak the file descriptor */
- }else{
- pOpen->aPending = aNew;
- pOpen->aPending[pOpen->nPending-1] = id->h;
- }
- }else{
- /* There are no outstanding locks so we can close the file immediately */
- close(id->h);
- }
- releaseLockInfo(id->pLock);
- releaseOpenCnt(id->pOpen);
- sqlite3OsLeaveMutex();
- id->isOpen = 0;
- TRACE2("CLOSE %-3d\n", id->h);
- OpenCounter(-1);
- return SQLITE_OK;
-}
-
-/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
@@ -944,6 +906,44 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
}
/*
+** Close a file.
+*/
+int sqlite3OsClose(OsFile *id){
+ if( !id->isOpen ) return SQLITE_OK;
+ sqlite3OsUnlock(id, NO_LOCK);
+ if( id->dirfd>=0 ) close(id->dirfd);
+ id->dirfd = -1;
+ sqlite3OsEnterMutex();
+ if( id->pOpen->nLock ){
+ /* If there are outstanding locks, do not actually close the file just
+ ** yet because that would clear those locks. Instead, add the file
+ ** descriptor to pOpen->aPending. It will be automatically closed when
+ ** the last lock is cleared.
+ */
+ int *aNew;
+ struct openCnt *pOpen = id->pOpen;
+ pOpen->nPending++;
+ aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) );
+ if( aNew==0 ){
+ /* If a malloc fails, just leak the file descriptor */
+ }else{
+ pOpen->aPending = aNew;
+ pOpen->aPending[pOpen->nPending-1] = id->h;
+ }
+ }else{
+ /* There are no outstanding locks so we can close the file immediately */
+ close(id->h);
+ }
+ releaseLockInfo(id->pLock);
+ releaseOpenCnt(id->pOpen);
+ sqlite3OsLeaveMutex();
+ id->isOpen = 0;
+ TRACE2("CLOSE %-3d\n", id->h);
+ OpenCounter(-1);
+ return SQLITE_OK;
+}
+
+/*
** Get information to seed the random number generator. The seed
** is written into the buffer zBuf[256]. The calling function must
** supply a sufficiently large buffer.
diff --git a/src/pager.c b/src/pager.c
index d3e3863fb..fb80b7d2d 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.133 2004/06/21 18:14:47 drh Exp $
+** @(#) $Id: pager.c,v 1.134 2004/06/22 11:29:02 danielk1977 Exp $
*/
#include "os.h" /* Must be first to enable large file support */
#include "sqliteInt.h"
@@ -2785,7 +2785,11 @@ sync_exit:
** PENDING_LOCK, or EXCLUSIVE_LOCK.
*/
int sqlite3pager_lockstate(Pager *pPager){
+#ifdef OS_TEST
+ return pPager->fd.fd.locktype;
+#else
return pPager->fd.locktype;
+#endif
}
#endif
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 3619855e1..a2a818f83 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,8 +11,11 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.297 2004/06/21 07:36:32 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.298 2004/06/22 11:29:02 danielk1977 Exp $
*/
+#ifndef _SQLITEINT_H_
+#define _SQLITEINT_H_
+
#include "config.h"
#include "sqlite3.h"
#include "hash.h"
@@ -1397,3 +1400,5 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew();
sqlite3_value *sqlite3GetTransientValue(sqlite *db);
+
+#endif
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index a033812f8..38c8974b5 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -675,7 +675,7 @@ void sqlite3VdbeSorterReset(Vdbe *p){
** Free all resources allociated with AggElem pElem, an element of
** aggregate pAgg.
*/
-int freeAggElem(AggElem *pElem, Agg *pAgg){
+void freeAggElem(AggElem *pElem, Agg *pAgg){
int i;
for(i=0; i<pAgg->nMem; i++){
Mem *pMem = &pElem->aMem[i];
@@ -719,7 +719,6 @@ int freeAggElem(AggElem *pElem, Agg *pAgg){
** for the next round of aggregate processing.
*/
int sqlite3VdbeAggReset(sqlite *db, Agg *pAgg, KeyInfo *pKeyInfo){
- int i;
int rc = 0;
BtCursor *pCsr = pAgg->pCsr;