Add demo code for a vfs that operates on a single pre-allocated file. (CVS 4429)
FossilOrigin-Name: 15680ca4821ec0652dfbe863199b4c3f2afad4ba
This commit is contained in:
parent
326c3fca85
commit
b61c16d987
1
main.mk
1
main.mk
@ -213,6 +213,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_hexio.c \
|
||||
$(TOP)/src/test_malloc.c \
|
||||
$(TOP)/src/test_md5.c \
|
||||
$(TOP)/src/test_onefile.c \
|
||||
$(TOP)/src/test_schema.c \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
|
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
||||
C Add\stests\sto\sprevent\sa\sregression\sof\sthe\sshort\sread\sproblem\sdiscovered\nin\sversion\s3.2.2.\s(CVS\s4428)
|
||||
D 2007-09-14T01:48:12
|
||||
C Add\sdemo\scode\sfor\sa\svfs\sthat\soperates\son\sa\ssingle\spre-allocated\sfile.\s(CVS\s4429)
|
||||
D 2007-09-14T16:19:27
|
||||
F Makefile.in cbfb898945536a8f9ea8b897e1586dd1fdbcc5db
|
||||
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -63,7 +63,7 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
|
||||
F ext/icu/icu.c 61a345d8126686aa3487aa8d2d0f68abd655f7a4
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387
|
||||
F main.mk e38d91102a2f8b70898e2817fe02aa656a02cb58
|
||||
F main.mk 5b05dad1fb7ce75200efe2c415b37ae9ff3575b4
|
||||
F mkdll.sh 37fa8a7412e51b5ab2bc6d4276135f022a0feffb
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 1a866b53637dab137191341cc875575a5ca110fb
|
||||
@ -153,6 +153,7 @@ F src/test_hexio.c 94a1efec4b19311eb7c4dc40e8496a3d8eadf18a
|
||||
F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8
|
||||
F src/test_malloc.c c34e7696dc4a5150c82452be28b87c7e38ba15ad
|
||||
F src/test_md5.c 34599caee5b1c73dcf86ca31f55846fab8c19ef7
|
||||
F src/test_onefile.c f545d497cdd25991e2ece107969737306bb89532
|
||||
F src/test_schema.c 12c9de7661d6294eec2d57afbb52e2af1128084f
|
||||
F src/test_server.c a6ece6c835e7eae835054124e09e947e422b1ac5
|
||||
F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59
|
||||
@ -377,6 +378,7 @@ F test/misc7.test a67af9620a510ce19f96ba69f3848228b7c62a73
|
||||
F test/misuse.test 30b3a458e5a70c31e74c291937b6c82204c59f33
|
||||
F test/notnull.test 44d600f916b770def8b095a9962dbe3be5a70d82
|
||||
F test/null.test 9503e1f63e959544c006d9f01709c5b5eab67d54
|
||||
F test/onefile.test 3b907ebfa5cc2ecd31d918776bb43fdf432b6618
|
||||
F test/openv2.test f5dd6b23e4dce828eb211649b600763c42a668df
|
||||
F test/pager.test 60303481b22b240c18d6dd1b64edcecc2f4b5a97
|
||||
F test/pager2.test c025f91b75fe65e85febda64d9416428b8a5cab5
|
||||
@ -578,7 +580,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P fec6567a0f8a868cda9bba2a473491dfb17b6c88
|
||||
R 64368b1c928a9ef5d9e681f8f2f0c32e
|
||||
U drh
|
||||
Z ca9ce5d0d5be2d28682a36a17ba9e364
|
||||
P 995c63b561e935b6a1da34590cb40582f5c30cee
|
||||
R 96d75dbd4f4bfe96dce3c4861d830f43
|
||||
U danielk1977
|
||||
Z b1ec5ccea80dfe40e173f2ee9efa6584
|
||||
|
@ -1 +1 @@
|
||||
995c63b561e935b6a1da34590cb40582f5c30cee
|
||||
15680ca4821ec0652dfbe863199b4c3f2afad4ba
|
820
src/test_onefile.c
Normal file
820
src/test_onefile.c
Normal file
@ -0,0 +1,820 @@
|
||||
/*
|
||||
** 2007 September 14
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** OVERVIEW:
|
||||
**
|
||||
** This file contains some example code demonstrating how the SQLite
|
||||
** vfs feature can be used to have SQLite operate directly on an
|
||||
** embedded media, without using an intermediate file system.
|
||||
**
|
||||
** Because this is only a demo designed to run on a workstation, the
|
||||
** underlying media is simulated using a regular file-system file. The
|
||||
** size of the file is fixed when it is first created (default size 10 MB).
|
||||
** From SQLite's point of view, this space is used to store a single
|
||||
** database file and the journal file.
|
||||
**
|
||||
** Any statement journal created is stored in volatile memory obtained
|
||||
** from sqlite3_malloc(). Any attempt to create a temporary database file
|
||||
** will fail (SQLITE_IOERR). To prevent SQLite from attempting this,
|
||||
** it should be configured to store all temporary database files in
|
||||
** main memory (see pragma "temp_store" or the TEMP_STORE compile time
|
||||
** option).
|
||||
**
|
||||
** ASSUMPTIONS:
|
||||
**
|
||||
** After it has been created, the blob file is accessed using the
|
||||
** following three functions only:
|
||||
**
|
||||
** mediaRead(); - Read a 512 byte block from the file.
|
||||
** mediaWrite(); - Write a 512 byte block to the file.
|
||||
** mediaSync(); - Tell the media hardware to sync.
|
||||
**
|
||||
** It is assumed that these can be easily implemented by any "real"
|
||||
** media vfs driver adapting this code.
|
||||
**
|
||||
** FILE FORMAT:
|
||||
**
|
||||
** The basic principle is that the "database file" is stored at the
|
||||
** beginning of the 10 MB blob and grows in a forward direction. The
|
||||
** "journal file" is stored at the end of the 10MB blob and grows
|
||||
** in the reverse direction. If, during a transaction, insufficient
|
||||
** space is available to expand either the journal or database file,
|
||||
** an SQLITE_FULL error is returned. The database file is never allowed
|
||||
** to consume more than 90% of the blob space. If SQLite tries to
|
||||
** create a file larger than this, SQLITE_FULL is returned.
|
||||
**
|
||||
** No allowance is made for "wear-leveling", as is required by.
|
||||
** embedded devices in the absence of equivalent hardware features.
|
||||
**
|
||||
** The first 512 block byte of the file is reserved for storing the
|
||||
** size of the "database file". It is updated as part of the sync()
|
||||
** operation. On startup, it can only be trusted if no journal file
|
||||
** exists. If a journal-file does exist, then it stores the real size
|
||||
** of the database region. The second and subsequent blocks store the
|
||||
** actual database content.
|
||||
**
|
||||
** The size of the "journal file" is not stored persistently in the
|
||||
** file. When the system is running, the size of the journal file is
|
||||
** stored in volatile memory. When recovering from a crash, this vfs
|
||||
** reports a very large size for the journal file. The normal journal
|
||||
** header and checksum mechanisms serve to prevent SQLite from
|
||||
** processing any data that lies past the logical end of the journal.
|
||||
**
|
||||
** When SQLite calls OsDelete() to delete the journal file, the final
|
||||
** 512 bytes of the blob (the area containing the first journal header)
|
||||
** are zeroed.
|
||||
**
|
||||
** LOCKING:
|
||||
**
|
||||
** File locking is a no-op. Only one connection may be open at any one
|
||||
** time using this demo vfs.
|
||||
*/
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Maximum pathname length supported by the fs backend.
|
||||
*/
|
||||
#define BLOCKSIZE 512
|
||||
#define BLOBSIZE 10485760
|
||||
|
||||
/*
|
||||
** Name used to identify this VFS.
|
||||
*/
|
||||
#define FS_VFS_NAME "fs"
|
||||
|
||||
typedef struct fs_real_file fs_real_file;
|
||||
struct fs_real_file {
|
||||
sqlite3_file *pFile;
|
||||
const char *zName;
|
||||
int nDatabase; /* Current size of database region */
|
||||
int nJournal; /* Current size of journal region */
|
||||
int nBlob; /* Total size of allocated blob */
|
||||
int nRef; /* Number of pointers to this structure */
|
||||
fs_real_file *pNext;
|
||||
fs_real_file **ppThis;
|
||||
};
|
||||
|
||||
typedef struct fs_file fs_file;
|
||||
struct fs_file {
|
||||
sqlite3_file base;
|
||||
int eType;
|
||||
fs_real_file *pReal;
|
||||
};
|
||||
|
||||
typedef struct tmp_file tmp_file;
|
||||
struct tmp_file {
|
||||
sqlite3_file base;
|
||||
int nSize;
|
||||
int nAlloc;
|
||||
char *zAlloc;
|
||||
};
|
||||
|
||||
/* Values for fs_file.eType. */
|
||||
#define DATABASE_FILE 1
|
||||
#define JOURNAL_FILE 2
|
||||
|
||||
/*
|
||||
** Method declarations for fs_file.
|
||||
*/
|
||||
static int fsClose(sqlite3_file*);
|
||||
static int fsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int fsWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int fsTruncate(sqlite3_file*, sqlite3_int64 size);
|
||||
static int fsSync(sqlite3_file*, int flags);
|
||||
static int fsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
||||
static int fsLock(sqlite3_file*, int);
|
||||
static int fsUnlock(sqlite3_file*, int);
|
||||
static int fsCheckReservedLock(sqlite3_file*);
|
||||
static int fsFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int fsSectorSize(sqlite3_file*);
|
||||
static int fsDeviceCharacteristics(sqlite3_file*);
|
||||
|
||||
/*
|
||||
** Method declarations for tmp_file.
|
||||
*/
|
||||
static int tmpClose(sqlite3_file*);
|
||||
static int tmpRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int tmpWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int tmpTruncate(sqlite3_file*, sqlite3_int64 size);
|
||||
static int tmpSync(sqlite3_file*, int flags);
|
||||
static int tmpFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
||||
static int tmpLock(sqlite3_file*, int);
|
||||
static int tmpUnlock(sqlite3_file*, int);
|
||||
static int tmpCheckReservedLock(sqlite3_file*);
|
||||
static int tmpFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int tmpSectorSize(sqlite3_file*);
|
||||
static int tmpDeviceCharacteristics(sqlite3_file*);
|
||||
|
||||
/*
|
||||
** Method declarations for fs_vfs.
|
||||
*/
|
||||
static int fsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
||||
static int fsDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
||||
static int fsAccess(sqlite3_vfs*, const char *zName, int flags);
|
||||
static int fsGetTempName(sqlite3_vfs*, char *zOut);
|
||||
static int fsFullPathname(sqlite3_vfs*, const char *zName, char *zOut);
|
||||
static void *fsDlOpen(sqlite3_vfs*, const char *zFilename);
|
||||
static void fsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
||||
static void *fsDlSym(sqlite3_vfs*,void*, const char *zSymbol);
|
||||
static void fsDlClose(sqlite3_vfs*, void*);
|
||||
static int fsRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
static int fsSleep(sqlite3_vfs*, int microseconds);
|
||||
static int fsCurrentTime(sqlite3_vfs*, double*);
|
||||
|
||||
|
||||
typedef struct fs_vfs_t fs_vfs_t;
|
||||
struct fs_vfs_t {
|
||||
sqlite3_vfs base;
|
||||
fs_real_file *pFileList;
|
||||
sqlite3_vfs *pParent;
|
||||
};
|
||||
|
||||
static fs_vfs_t fs_vfs = {
|
||||
{
|
||||
1, /* iVersion */
|
||||
0, /* szOsFile */
|
||||
0, /* mxPathname */
|
||||
0, /* pNext */
|
||||
FS_VFS_NAME, /* zName */
|
||||
0, /* pAppData */
|
||||
fsOpen, /* xOpen */
|
||||
fsDelete, /* xDelete */
|
||||
fsAccess, /* xAccess */
|
||||
fsGetTempName, /* xGetTempName */
|
||||
fsFullPathname, /* xFullPathname */
|
||||
fsDlOpen, /* xDlOpen */
|
||||
fsDlError, /* xDlError */
|
||||
fsDlSym, /* xDlSym */
|
||||
fsDlClose, /* xDlClose */
|
||||
fsRandomness, /* xRandomness */
|
||||
fsSleep, /* xSleep */
|
||||
fsCurrentTime /* xCurrentTime */
|
||||
},
|
||||
0, /* pFileList */
|
||||
0 /* pParent */
|
||||
};
|
||||
|
||||
static sqlite3_io_methods fs_io_methods = {
|
||||
1, /* iVersion */
|
||||
fsClose, /* xClose */
|
||||
fsRead, /* xRead */
|
||||
fsWrite, /* xWrite */
|
||||
fsTruncate, /* xTruncate */
|
||||
fsSync, /* xSync */
|
||||
fsFileSize, /* xFileSize */
|
||||
fsLock, /* xLock */
|
||||
fsUnlock, /* xUnlock */
|
||||
fsCheckReservedLock, /* xCheckReservedLock */
|
||||
fsFileControl, /* xFileControl */
|
||||
fsSectorSize, /* xSectorSize */
|
||||
fsDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
};
|
||||
|
||||
|
||||
static sqlite3_io_methods tmp_io_methods = {
|
||||
1, /* iVersion */
|
||||
tmpClose, /* xClose */
|
||||
tmpRead, /* xRead */
|
||||
tmpWrite, /* xWrite */
|
||||
tmpTruncate, /* xTruncate */
|
||||
tmpSync, /* xSync */
|
||||
tmpFileSize, /* xFileSize */
|
||||
tmpLock, /* xLock */
|
||||
tmpUnlock, /* xUnlock */
|
||||
tmpCheckReservedLock, /* xCheckReservedLock */
|
||||
tmpFileControl, /* xFileControl */
|
||||
tmpSectorSize, /* xSectorSize */
|
||||
tmpDeviceCharacteristics /* xDeviceCharacteristics */
|
||||
};
|
||||
|
||||
/* Useful macros used in several places */
|
||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
||||
#define MAX(x,y) ((x)>(y)?(x):(y))
|
||||
|
||||
|
||||
/*
|
||||
** Close a tmp-file.
|
||||
*/
|
||||
static int tmpClose(sqlite3_file *pFile){
|
||||
tmp_file *pTmp = (tmp_file *)pFile;
|
||||
sqlite3_free(pTmp->zAlloc);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a tmp-file.
|
||||
*/
|
||||
static int tmpRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
tmp_file *pTmp = (tmp_file *)pFile;
|
||||
if( (iAmt+iOfst)>pTmp->nSize ){
|
||||
return SQLITE_IOERR_SHORT_READ;
|
||||
}
|
||||
memcpy(zBuf, &pTmp->zAlloc[iOfst], iAmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to a tmp-file.
|
||||
*/
|
||||
static int tmpWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
tmp_file *pTmp = (tmp_file *)pFile;
|
||||
if( (iAmt+iOfst)>pTmp->nAlloc ){
|
||||
int nNew = 2*(iAmt+iOfst+pTmp->nAlloc);
|
||||
char *zNew = sqlite3_realloc(pTmp->zAlloc, nNew);
|
||||
if( !zNew ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pTmp->zAlloc = zNew;
|
||||
pTmp->nAlloc = nNew;
|
||||
}
|
||||
memcpy(&pTmp->zAlloc[iOfst], zBuf, iAmt);
|
||||
pTmp->nSize = MAX(pTmp->nSize, iOfst+iAmt);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate a tmp-file.
|
||||
*/
|
||||
static int tmpTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
tmp_file *pTmp = (tmp_file *)pFile;
|
||||
pTmp->nSize = MIN(pTmp->nSize, size);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync a tmp-file.
|
||||
*/
|
||||
static int tmpSync(sqlite3_file *pFile, int flags){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current file-size of a tmp-file.
|
||||
*/
|
||||
static int tmpFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
tmp_file *pTmp = (tmp_file *)pFile;
|
||||
*pSize = pTmp->nSize;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock a tmp-file.
|
||||
*/
|
||||
static int tmpLock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock a tmp-file.
|
||||
*/
|
||||
static int tmpUnlock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if another file-handle holds a RESERVED lock on a tmp-file.
|
||||
*/
|
||||
static int tmpCheckReservedLock(sqlite3_file *pFile){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** File control method. For custom operations on a tmp-file.
|
||||
*/
|
||||
static int tmpFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for a tmp-file.
|
||||
*/
|
||||
static int tmpSectorSize(sqlite3_file *pFile){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by a tmp-file.
|
||||
*/
|
||||
static int tmpDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an fs-file.
|
||||
*/
|
||||
static int fsClose(sqlite3_file *pFile){
|
||||
int rc = SQLITE_OK;
|
||||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = p->pReal;
|
||||
|
||||
/* Decrement the real_file ref-count. */
|
||||
pReal->nRef--;
|
||||
assert(pReal->nRef>=0);
|
||||
|
||||
/* When the ref-count reaches 0, destroy the structure */
|
||||
if( pReal->nRef==0 ){
|
||||
*pReal->ppThis = pReal->pNext;
|
||||
if( pReal->pNext ){
|
||||
pReal->pNext->ppThis = pReal->ppThis;
|
||||
}
|
||||
rc = pReal->pFile->pMethods->xClose(pReal->pFile);
|
||||
sqlite3_free(pReal);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from an fs-file.
|
||||
*/
|
||||
static int fsRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = p->pReal;
|
||||
sqlite3_file *pF = pReal->pFile;
|
||||
|
||||
if( (p->eType==DATABASE_FILE && (iAmt+iOfst)>pReal->nDatabase)
|
||||
|| (p->eType==JOURNAL_FILE && (iAmt+iOfst)>pReal->nJournal)
|
||||
){
|
||||
rc = SQLITE_IOERR_SHORT_READ;
|
||||
}else if( p->eType==DATABASE_FILE ){
|
||||
rc = pF->pMethods->xRead(pF, zBuf, iAmt, iOfst+BLOCKSIZE);
|
||||
}else{
|
||||
/* Journal file. */
|
||||
int iRem = iAmt;
|
||||
int iBuf = 0;
|
||||
int ii = iOfst;
|
||||
while( iRem>0 && rc==SQLITE_OK ){
|
||||
int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
|
||||
int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
|
||||
|
||||
rc = pF->pMethods->xRead(pF, &((char *)zBuf)[iBuf], iRealAmt, iRealOff);
|
||||
ii += iRealAmt;
|
||||
iBuf += iRealAmt;
|
||||
iRem -= iRealAmt;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to an fs-file.
|
||||
*/
|
||||
static int fsWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = p->pReal;
|
||||
sqlite3_file *pF = pReal->pFile;
|
||||
|
||||
if( p->eType==DATABASE_FILE ){
|
||||
if( (iAmt+iOfst+BLOCKSIZE)>(pReal->nBlob-pReal->nJournal) ){
|
||||
rc = SQLITE_FULL;
|
||||
}else{
|
||||
rc = pF->pMethods->xWrite(pF, zBuf, iAmt, iOfst+BLOCKSIZE);
|
||||
if( rc==SQLITE_OK ){
|
||||
pReal->nDatabase = MAX(pReal->nDatabase, iAmt+iOfst);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
/* Journal file. */
|
||||
int iRem = iAmt;
|
||||
int iBuf = 0;
|
||||
int ii = iOfst;
|
||||
while( iRem>0 && rc==SQLITE_OK ){
|
||||
int iRealOff = pReal->nBlob - BLOCKSIZE*((ii/BLOCKSIZE)+1) + ii%BLOCKSIZE;
|
||||
int iRealAmt = MIN(iRem, BLOCKSIZE - (iRealOff%BLOCKSIZE));
|
||||
|
||||
if( iRealOff<(pReal->nDatabase+BLOCKSIZE) ){
|
||||
rc = SQLITE_FULL;
|
||||
}else{
|
||||
rc = pF->pMethods->xWrite(pF, &((char *)zBuf)[iBuf], iRealAmt,iRealOff);
|
||||
ii += iRealAmt;
|
||||
iBuf += iRealAmt;
|
||||
iRem -= iRealAmt;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pReal->nJournal = MAX(pReal->nJournal, iAmt+iOfst);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate an fs-file.
|
||||
*/
|
||||
static int fsTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = p->pReal;
|
||||
if( p->eType==DATABASE_FILE ){
|
||||
pReal->nDatabase = MIN(pReal->nDatabase, size);
|
||||
}else{
|
||||
pReal->nJournal = MIN(pReal->nJournal, size);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync an fs-file.
|
||||
*/
|
||||
static int fsSync(sqlite3_file *pFile, int flags){
|
||||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = p->pReal;
|
||||
sqlite3_file *pRealFile = pReal->pFile;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( p->eType==DATABASE_FILE ){
|
||||
unsigned char zSize[4];
|
||||
zSize[0] = (pReal->nDatabase&0xFF000000)>>24;
|
||||
zSize[1] = (pReal->nDatabase&0x00FF0000)>>16;
|
||||
zSize[2] = (pReal->nDatabase&0x0000FF00)>>8;
|
||||
zSize[3] = (pReal->nDatabase&0x000000FF);
|
||||
rc = pRealFile->pMethods->xWrite(pRealFile, zSize, 4, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pRealFile->pMethods->xSync(pRealFile, flags&(~SQLITE_SYNC_DATAONLY));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current file-size of an fs-file.
|
||||
*/
|
||||
static int fsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = p->pReal;
|
||||
if( p->eType==DATABASE_FILE ){
|
||||
*pSize = pReal->nDatabase;
|
||||
}else{
|
||||
*pSize = pReal->nJournal;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock an fs-file.
|
||||
*/
|
||||
static int fsLock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock an fs-file.
|
||||
*/
|
||||
static int fsUnlock(sqlite3_file *pFile, int eLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if another file-handle holds a RESERVED lock on an fs-file.
|
||||
*/
|
||||
static int fsCheckReservedLock(sqlite3_file *pFile){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** File control method. For custom operations on an fs-file.
|
||||
*/
|
||||
static int fsFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for an fs-file.
|
||||
*/
|
||||
static int fsSectorSize(sqlite3_file *pFile){
|
||||
return BLOCKSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by an fs-file.
|
||||
*/
|
||||
static int fsDeviceCharacteristics(sqlite3_file *pFile){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open an fs file handle.
|
||||
*/
|
||||
static int fsOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
|
||||
fs_file *p = (fs_file *)pFile;
|
||||
fs_real_file *pReal = 0;
|
||||
int eType;
|
||||
int nName;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
if( 0==(flags&(SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_MAIN_JOURNAL)) ){
|
||||
tmp_file *p = (tmp_file *)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->base.pMethods = &tmp_io_methods;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
eType = ((flags&(SQLITE_OPEN_MAIN_DB))?DATABASE_FILE:JOURNAL_FILE);
|
||||
p->base.pMethods = &fs_io_methods;
|
||||
p->eType = eType;
|
||||
|
||||
assert(strlen("-journal")==8);
|
||||
nName = strlen(zName)-((eType==JOURNAL_FILE)?8:0);
|
||||
pReal=pFsVfs->pFileList;
|
||||
for(; pReal && strncmp(pReal->zName, zName, nName); pReal=pReal->pNext);
|
||||
|
||||
if( !pReal ){
|
||||
sqlite3_int64 size;
|
||||
sqlite3_file *pRealFile;
|
||||
sqlite3_vfs *pParent = pFsVfs->pParent;
|
||||
assert(eType==DATABASE_FILE);
|
||||
|
||||
pReal = (fs_real_file *)sqlite3_malloc(sizeof(*pReal)+pParent->szOsFile);
|
||||
if( !pReal ){
|
||||
rc = SQLITE_NOMEM;
|
||||
goto open_out;
|
||||
}
|
||||
memset(pReal, 0, sizeof(*pReal)+pParent->szOsFile);
|
||||
pReal->zName = zName;
|
||||
pReal->pFile = (sqlite3_file *)(&pReal[1]);
|
||||
|
||||
rc = pParent->xOpen(pParent, zName, pReal->pFile, flags, pOutFlags);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto open_out;
|
||||
}
|
||||
pRealFile = pReal->pFile;
|
||||
|
||||
rc = pRealFile->pMethods->xFileSize(pRealFile, &size);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto open_out;
|
||||
}
|
||||
if( size==0 ){
|
||||
rc = pRealFile->pMethods->xWrite(pRealFile, "\0", 1, BLOBSIZE-1);
|
||||
pReal->nBlob = BLOBSIZE;
|
||||
}else{
|
||||
unsigned char zS[4];
|
||||
pReal->nBlob = size;
|
||||
rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, 0);
|
||||
pReal->nDatabase = (zS[0]<<24)+(zS[1]<<16)+(zS[2]<<8)+zS[3];
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pRealFile->pMethods->xRead(pRealFile, zS, 4, pReal->nBlob-4);
|
||||
if( zS[0] || zS[1] || zS[2] || zS[3] ){
|
||||
pReal->nJournal = pReal->nBlob;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pReal->pNext = pFsVfs->pFileList;
|
||||
if( pReal->pNext ){
|
||||
pReal->pNext->ppThis = &pReal->pNext;
|
||||
}
|
||||
pReal->ppThis = &pFsVfs->pFileList;
|
||||
pFsVfs->pFileList = pReal;
|
||||
}
|
||||
}
|
||||
|
||||
open_out:
|
||||
if( pReal ){
|
||||
if( rc==SQLITE_OK ){
|
||||
p->pReal = pReal;
|
||||
pReal->nRef++;
|
||||
}else{
|
||||
if( pReal->pFile->pMethods ){
|
||||
pReal->pFile->pMethods->xClose(pReal->pFile);
|
||||
}
|
||||
sqlite3_free(pReal);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the file located at zPath. If the dirSync argument is true,
|
||||
** ensure the file-system modifications are synced to disk before
|
||||
** returning.
|
||||
*/
|
||||
static int fsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
int rc = SQLITE_OK;
|
||||
fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
|
||||
fs_real_file *pReal;
|
||||
sqlite3_file *pF;
|
||||
int nName = strlen(zPath) - 8;
|
||||
|
||||
assert(strlen("-journal")==8);
|
||||
assert(strcmp("-journal", &zPath[nName])==0);
|
||||
|
||||
pReal = pFsVfs->pFileList;
|
||||
for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
|
||||
if( pReal ){
|
||||
pF = pReal->pFile;
|
||||
rc = pF->pMethods->xWrite(pF, "\0\0\0\0", 4, pReal->nBlob-BLOCKSIZE);
|
||||
if( rc==SQLITE_OK ){
|
||||
pReal->nJournal = 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Test for access permissions. Return true if the requested permission
|
||||
** is available, or false otherwise.
|
||||
*/
|
||||
static int fsAccess(sqlite3_vfs *pVfs, const char *zPath, int flags){
|
||||
fs_vfs_t *pFsVfs = (fs_vfs_t *)pVfs;
|
||||
fs_real_file *pReal;
|
||||
int isJournal = 0;
|
||||
int nName = strlen(zPath);
|
||||
|
||||
if( flags!=SQLITE_ACCESS_EXISTS ){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xAccess(pParent, zPath, flags);
|
||||
}
|
||||
|
||||
assert(strlen("-journal")==8);
|
||||
if( nName>8 && strcmp("-journal", &zPath[nName-8])==0 ){
|
||||
nName -= 8;
|
||||
isJournal = 1;
|
||||
}
|
||||
|
||||
pReal = pFsVfs->pFileList;
|
||||
for(; pReal && strncmp(pReal->zName, zPath, nName); pReal=pReal->pNext);
|
||||
if( !pReal ) return 0;
|
||||
return ((!isJournal||pReal->nJournal>0)?1:0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate buffer zBufOut with a pathname suitable for use as a
|
||||
** temporary file. zBufOut is guaranteed to point to a buffer of
|
||||
** at least (FS_MAX_PATHNAME+1) bytes.
|
||||
*/
|
||||
static int fsGetTempName(sqlite3_vfs *pVfs, char *zBufOut){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xGetTempName(pParent, zBufOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate buffer zOut with the full canonical pathname corresponding
|
||||
** to the pathname in zPath. zOut is guaranteed to point to a buffer
|
||||
** of at least (FS_MAX_PATHNAME+1) bytes.
|
||||
*/
|
||||
static int fsFullPathname(sqlite3_vfs *pVfs, const char *zPath, char *zOut){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xFullPathname(pParent, zPath, zOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open the dynamic library located at zPath and return a handle.
|
||||
*/
|
||||
static void *fsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xDlOpen(pParent, zPath);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
|
||||
** utf-8 string describing the most recent error encountered associated
|
||||
** with dynamic libraries.
|
||||
*/
|
||||
static void fsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
pParent->xDlError(pParent, nByte, zErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
|
||||
*/
|
||||
static void *fsDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xDlSym(pParent, pHandle, zSymbol);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the dynamic library handle pHandle.
|
||||
*/
|
||||
static void fsDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
pParent->xDlClose(pParent, pHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer pointed to by zBufOut with nByte bytes of
|
||||
** random data.
|
||||
*/
|
||||
static int fsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xRandomness(pParent, nByte, zBufOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Sleep for nMicro microseconds. Return the number of microseconds
|
||||
** actually slept.
|
||||
*/
|
||||
static int fsSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xSleep(pParent, nMicro);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current time as a Julian Day number in *pTimeOut.
|
||||
*/
|
||||
static int fsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
sqlite3_vfs *pParent = ((fs_vfs_t *)pVfs)->pParent;
|
||||
return pParent->xCurrentTime(pParent, pTimeOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** This procedure registers the fs vfs with SQLite. If the argument is
|
||||
** true, the fs vfs becomes the new default vfs. It is the only publicly
|
||||
** available function in this file.
|
||||
*/
|
||||
int fs_register(){
|
||||
if( fs_vfs.pParent ) return SQLITE_OK;
|
||||
fs_vfs.pParent = sqlite3_vfs_find(0);
|
||||
fs_vfs.base.mxPathname = fs_vfs.pParent->mxPathname;
|
||||
fs_vfs.base.szOsFile = MAX(sizeof(tmp_file), sizeof(fs_file));
|
||||
return sqlite3_vfs_register(&fs_vfs.base, 0);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_TEST
|
||||
int SqlitetestOnefile_Init() {return fs_register();}
|
||||
#endif
|
||||
|
55
test/onefile.test
Normal file
55
test/onefile.test
Normal file
@ -0,0 +1,55 @@
|
||||
#
|
||||
# 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 runs all tests.
|
||||
#
|
||||
# $Id: onefile.test,v 1.1 2007/09/14 16:19:27 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
rename finish_test really_finish_test
|
||||
proc finish_test {} {
|
||||
catch {db close}
|
||||
catch {db2 close}
|
||||
catch {db3 close}
|
||||
}
|
||||
set ISQUICK 1
|
||||
|
||||
set INCLUDE {
|
||||
conflict.test
|
||||
insert.test
|
||||
insert2.test
|
||||
insert3.test
|
||||
rollback.test
|
||||
select1.test
|
||||
select2.test
|
||||
select3.test
|
||||
temptable.test
|
||||
}
|
||||
#set INCLUDE insert2.test
|
||||
|
||||
rename sqlite3 really_sqlite3
|
||||
proc sqlite3 {args} {
|
||||
if {[string range [lindex $args 0] 0 0] ne "-"} {
|
||||
lappend args -vfs fs
|
||||
}
|
||||
uplevel [concat really_sqlite3 $args]
|
||||
}
|
||||
|
||||
rename do_test really_do_test
|
||||
proc do_test {name args} {
|
||||
uplevel really_do_test onefile-$name $args
|
||||
}
|
||||
|
||||
foreach testfile [lsort -dictionary [glob $testdir/*.test]] {
|
||||
set tail [file tail $testfile]
|
||||
if {[lsearch -exact $INCLUDE $tail]<0} continue
|
||||
source $testfile
|
||||
}
|
||||
|
||||
really_finish_test
|
||||
rename really_do_test do_test
|
||||
rename really_finish_test finish_test
|
Loading…
Reference in New Issue
Block a user