wasCSharpSQLite – Rev 1
?pathlinks?
using System;
using System.Diagnostics;
using System.Text;
using Bitmask = System.UInt64;
using u8 = System.Byte;
using u16 = System.UInt16;
using u32 = System.UInt32;
namespace Community.CsharpSqlite
{
using sqlite3_int64 = System.Int64;
using MemJournal = Sqlite3.sqlite3_file;
public partial class Sqlite3
{
/*
** 2007 August 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 use to implement an in-memory rollback journal.
** The in-memory rollback journal is used to journal transactions for
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
*************************************************************************
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
** C#-SQLite is an independent reimplementation of the SQLite software library
**
** SQLITE_SOURCE_ID: 2010-12-07 20:14:09 a586a4deeb25330037a49df295b36aaf624d0f45
**
*************************************************************************
*/
//#include "sqliteInt.h"
/* Forward references to internal structures */
//typedef struct MemJournal MemJournal;
//typedef struct FilePoint FilePoint;
//typedef struct FileChunk FileChunk;
/* Space to hold the rollback journal is allocated in increments of
** this many bytes.
**
** The size chosen is a little less than a power of two. That way,
** the FileChunk object will have a size that almost exactly fills
** a power-of-two allocation. This mimimizes wasted space in power-of-two
** memory allocators.
*/
//#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
const int JOURNAL_CHUNKSIZE = 4096;
/* Macro to find the minimum of two numeric values.
*/
//#if !MIN
//# define MIN(x,y) ((x)<(y)?(x):(y))
//#endif
static int MIN( int x, int y )
{
return ( x < y ) ? x : y;
}
static int MIN( int x, u32 y )
{
return ( x < y ) ? x : (int)y;
}
/*
** The rollback journal is composed of a linked list of these structures.
*/
public class FileChunk
{
public FileChunk pNext; /* Next chunk in the journal */
public byte[] zChunk = new byte[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
};
/*
** An instance of this object serves as a cursor into the rollback journal.
** The cursor can be either for reading or writing.
*/
public class FilePoint
{
public long iOffset; /* Offset from the beginning of the file */
public FileChunk pChunk; /* Specific chunk into which cursor points */
};
/*
** This subclass is a subclass of sqlite3_file. Each open memory-journal
** is an instance of this class.
*/
public partial class sqlite3_file
{
//public sqlite3_io_methods pMethods; /* Parent class. MUST BE FIRST */
public FileChunk pFirst; /* Head of in-memory chunk-list */
public FilePoint endpoint; /* Pointer to the end of the file */
public FilePoint readpoint; /* Pointer to the end of the last xRead() */
};
/*
** Read data from the in-memory journal file. This is the implementation
** of the sqlite3_vfs.xRead method.
*/
static int memjrnlRead(
sqlite3_file pJfd, /* The journal file from which to read */
byte[] zBuf, /* Put the results here */
int iAmt, /* Number of bytes to read */
sqlite3_int64 iOfst /* Begin reading at this offset */
)
{
MemJournal p = (MemJournal)pJfd;
byte[] zOut = zBuf;
int nRead = iAmt;
int iChunkOffset;
FileChunk pChunk;
/* SQLite never tries to read past the end of a rollback journal file */
Debug.Assert( iOfst + iAmt <= p.endpoint.iOffset );
if ( p.readpoint.iOffset != iOfst || iOfst == 0 )
{
int iOff = 0;
for ( pChunk = p.pFirst;
ALWAYS( pChunk != null ) && ( iOff + JOURNAL_CHUNKSIZE ) <= iOfst;
pChunk = pChunk.pNext
)
{
iOff += JOURNAL_CHUNKSIZE;
}
}
else
{
pChunk = p.readpoint.pChunk;
}
iChunkOffset = (int)( iOfst % JOURNAL_CHUNKSIZE );
int izOut = 0;
do
{
int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
int nCopy = MIN( nRead, ( JOURNAL_CHUNKSIZE - iChunkOffset ) );
Buffer.BlockCopy( pChunk.zChunk, iChunkOffset, zOut, izOut, nCopy ); //memcpy( zOut, pChunk.zChunk[iChunkOffset], nCopy );
izOut += nCopy;// zOut += nCopy;
nRead -= iSpace;
iChunkOffset = 0;
} while ( nRead >= 0 && ( pChunk = pChunk.pNext ) != null && nRead > 0 );
p.readpoint.iOffset = (int)( iOfst + iAmt );
p.readpoint.pChunk = pChunk;
return SQLITE_OK;
}
/*
** Write data to the file.
*/
static int memjrnlWrite(
sqlite3_file pJfd, /* The journal file into which to write */
byte[] zBuf, /* Take data to be written from here */
int iAmt, /* Number of bytes to write */
sqlite3_int64 iOfst /* Begin writing at this offset into the file */
)
{
MemJournal p = (MemJournal)pJfd;
int nWrite = iAmt;
byte[] zWrite = zBuf;
int izWrite = 0;
/* An in-memory journal file should only ever be appended to. Random
** access writes are not required by sqlite.
*/
Debug.Assert( iOfst == p.endpoint.iOffset );
UNUSED_PARAMETER( iOfst );
while ( nWrite > 0 )
{
FileChunk pChunk = p.endpoint.pChunk;
int iChunkOffset = (int)( p.endpoint.iOffset % JOURNAL_CHUNKSIZE );
int iSpace = MIN( nWrite, JOURNAL_CHUNKSIZE - iChunkOffset );
if ( iChunkOffset == 0 )
{
/* New chunk is required to extend the file. */
FileChunk pNew = new FileChunk();// sqlite3_malloc( sizeof( FileChunk ) );
if ( null == pNew )
{
return SQLITE_IOERR_NOMEM;
}
pNew.pNext = null;
if ( pChunk != null )
{
Debug.Assert( p.pFirst != null );
pChunk.pNext = pNew;
}
else
{
Debug.Assert( null == p.pFirst );
p.pFirst = pNew;
}
p.endpoint.pChunk = pNew;
}
Buffer.BlockCopy( zWrite, izWrite, p.endpoint.pChunk.zChunk, iChunkOffset, iSpace ); //memcpy( &p.endpoint.pChunk.zChunk[iChunkOffset], zWrite, iSpace );
izWrite += iSpace;//zWrite += iSpace;
nWrite -= iSpace;
p.endpoint.iOffset += iSpace;
}
return SQLITE_OK;
}
/*
** Truncate the file.
*/
static int memjrnlTruncate( sqlite3_file pJfd, sqlite3_int64 size )
{
MemJournal p = (MemJournal)pJfd;
FileChunk pChunk;
Debug.Assert( size == 0 );
UNUSED_PARAMETER( size );
pChunk = p.pFirst;
while ( pChunk != null )
{
////FileChunk pTmp = pChunk;
pChunk = pChunk.pNext;
//sqlite3_free( ref pTmp );
}
sqlite3MemJournalOpen( pJfd );
return SQLITE_OK;
}
/*
** Close the file.
*/
static int memjrnlClose( MemJournal pJfd )
{
memjrnlTruncate( pJfd, 0 );
return SQLITE_OK;
}
/*
** Sync the file.
**
** Syncing an in-memory journal is a no-op. And, in fact, this routine
** is never called in a working implementation. This implementation
** exists purely as a contingency, in case some malfunction in some other
** part of SQLite causes Sync to be called by mistake.
*/
static int memjrnlSync( sqlite3_file NotUsed, int NotUsed2 )
{
UNUSED_PARAMETER2( NotUsed, NotUsed2 );
return SQLITE_OK;
}
/*
** Query the size of the file in bytes.
*/
static int memjrnlFileSize( sqlite3_file pJfd, ref long pSize )
{
MemJournal p = (MemJournal)pJfd;
pSize = p.endpoint.iOffset;
return SQLITE_OK;
}
/*
** Table of methods for MemJournal sqlite3_file object.
*/
static sqlite3_io_methods MemJournalMethods = new sqlite3_io_methods(
1, /* iVersion */
(dxClose)memjrnlClose, /* xClose */
(dxRead)memjrnlRead, /* xRead */
(dxWrite)memjrnlWrite, /* xWrite */
(dxTruncate)memjrnlTruncate, /* xTruncate */
(dxSync)memjrnlSync, /* xSync */
(dxFileSize)memjrnlFileSize, /* xFileSize */
null, /* xLock */
null, /* xUnlock */
null, /* xCheckReservedLock */
null, /* xFileControl */
null, /* xSectorSize */
null, /* xDeviceCharacteristics */
null, /* xShmMap */
null, /* xShmLock */
null, /* xShmBarrier */
null /* xShmUnlock */
);
/*
** Open a journal file.
*/
static void sqlite3MemJournalOpen( sqlite3_file pJfd )
{
MemJournal p = (MemJournal)pJfd;
//memset( p, 0, sqlite3MemJournalSize() );
p.pFirst = null;
p.endpoint = new FilePoint();
p.readpoint = new FilePoint();
p.pMethods = MemJournalMethods;//(sqlite3_io_methods*)&MemJournalMethods;
}
/*
** Return true if the file-handle passed as an argument is
** an in-memory journal
*/
static bool sqlite3IsMemJournal( sqlite3_file pJfd )
{
return pJfd.pMethods == MemJournalMethods;
}
/*
** Return the number of bytes required to store a MemJournal file descriptor.
*/
static int sqlite3MemJournalSize()
{
return 3096; // sizeof( MemJournal );
}
}
}