wasCSharpSQLite – Rev 3
?pathlinks?
using System;
using System.Diagnostics;
using System.Text;
using u8 = System.Byte;
using u32 = System.UInt32;
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite_int64 = System.Int64;
using sqlite3_int64 = System.Int64;
using sqlite3_stmt = Community.CsharpSqlite.Sqlite3.Vdbe;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
public partial class Sqlite3
{
/*
** 2010 May 05
**
** 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 the implementation of the Tcl [testvfs] command,
** used to create SQLite VFS implementations with various properties and
** instrumentation to support testing SQLite.
**
** testvfs VFSNAME ?OPTIONS?
**
** Available options are:
**
** -noshm BOOLEAN (True to omit shm methods. Default false)
** -default BOOLEAN (True to make the vfs default. Default false)
** -szosfile INTEGER (Value for sqlite3_vfs.szOsFile)
** -mxpathname INTEGER (Value for sqlite3_vfs.mxPathname)
** -iversion INTEGER (Value for sqlite3_vfs.iVersion)
*/
#if SQLITE_TEST //* This file is used for testing only */
//#include "sqlite3.h"
//#include "sqliteInt.h"
//typedef struct Testvfs Testvfs;
//typedef struct TestvfsShm TestvfsShm;
//typedef struct TestvfsBuffer TestvfsBuffer;
//typedef struct TestvfsFile TestvfsFile;
//typedef struct TestvfsFd TestvfsFd;
/*
** An open file handle.
*/
class TestvfsFile : sqlite3_file
{
//public sqlite3_file base; /* Base class. Must be first */
public TestvfsFd pFd; /* File data */
};
//#define tvfsGetFd(pFile) (((TestvfsFile )pFile)->pFd)
static TestvfsFd tvfsGetFd( sqlite3_file pFile )
{
return ((TestvfsFile)pFile).pFd;
}
class TestvfsFd {
public sqlite3_vfs pVfs; /* The VFS */
public string zFilename; /* Filename as passed to xOpen() */
public sqlite3_file pReal; /* The real, underlying file descriptor */
public Tcl_Obj pShmId; /* Shared memory id for Tcl callbacks */
public TestvfsBuffer pShm; /* Shared memory buffer */
public u32 excllock; /* Mask of exclusive locks */
public u32 sharedlock; /* Mask of shared locks */
public TestvfsFd pNext; /* Next handle opened on the same file */
};
//#define FAULT_INJECT_NONE 0
//#define FAULT_INJECT_TRANSIENT 1
//#define FAULT_INJECT_PERSISTENT 2
const int FAULT_INJECT_NONE = 0;
const int FAULT_INJECT_TRANSIENT = 1;
const int FAULT_INJECT_PERSISTENT = 2;
//typedef struct TestFaultInject TestFaultInject;
class TestFaultInject {
public int iCnt; /* Remaining calls before fault injection */
public int eFault; /* A FAULT_INJECT_* value */
public int nFail; /* Number of faults injected */
};
/*
** An instance of this structure is allocated for each VFS created. The
** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite
** is set to point to it.
*/
class Testvfs {
public string zName; /* Name of this VFS */
public sqlite3_vfs pParent; /* The VFS to use for file IO */
public sqlite3_vfs pVfs; /* The testvfs registered with SQLite */
public Tcl_Interp interp; /* Interpreter to run script in */
public Tcl_Obj pScript; /* Script to execute */
public TestvfsBuffer pBuffer; /* List of shared buffers */
public int isNoshm;
public int mask; /* Mask controlling [script] and [ioerr] */
public TestFaultInject ioerr_err;
public TestFaultInject full_err;
public TestFaultInject cantopen_err;
#if FALSE
public int iIoerrCnt;
public int ioerr;
public int nIoerrFail;
public int iFullCnt;
public int fullerr;
public int nFullFail;
#endif
public int iDevchar;
public int iSectorsize;
};
/*
** The Testvfs.mask variable is set to a combination of the following.
** If a bit is clear in Testvfs.mask, then calls made by SQLite to the
** corresponding VFS method is ignored for purposes of:
**
** + Simulating IO errors, and
** + Invoking the Tcl callback script.
*/
//#define TESTVFS_SHMOPEN_MASK 0x00000001
//#define TESTVFS_SHMLOCK_MASK 0x00000010
//#define TESTVFS_SHMMAP_MASK 0x00000020
//#define TESTVFS_SHMBARRIER_MASK 0x00000040
//#define TESTVFS_SHMCLOSE_MASK 0x00000080
const int TESTVFS_SHMOPEN_MASK =0x00000001;
const int TESTVFS_SHMLOCK_MASK =0x00000010;
const int TESTVFS_SHMMAP_MASK =0x00000020;
const int TESTVFS_SHMBARRIER_MASK =0x00000040;
const int TESTVFS_SHMCLOSE_MASK =0x00000080;
//#define TESTVFS_OPEN_MASK 0x00000100
//#define TESTVFS_SYNC_MASK 0x00000200
//#define TESTVFS_DELETE_MASK 0x00000400
//#define TESTVFS_CLOSE_MASK 0x00000800
//#define TESTVFS_WRITE_MASK 0x00001000
//#define TESTVFS_TRUNCATE_MASK 0x00002000
//#define TESTVFS_ACCESS_MASK 0x00004000
//#define TESTVFS_FULLPATHNAME_MASK 0x00008000
//#define TESTVFS_ALL_MASK 0x0001FFFF
const int TESTVFS_OPEN_MASK =0x00000100;
const int TESTVFS_SYNC_MASK =0x00000200;
const int TESTVFS_DELETE_MASK =0x00000400;
const int TESTVFS_CLOSE_MASK =0x00000800;
const int TESTVFS_WRITE_MASK =0x00001000;
const int TESTVFS_TRUNCATE_MASK =0x00002000;
const int TESTVFS_ACCESS_MASK =0x00004000;
const int TESTVFS_FULLPATHNAME_MASK =0x00008000;
const int TESTVFS_ALL_MASK =0x0001FFFF;
//#define TESTVFS_MAX_PAGES 1024
const int TESTVFS_MAX_PAGES =1024;
/*
** A shared-memory buffer. There is one of these objects for each shared
** memory region opened by clients. If two clients open the same file,
** there are two TestvfsFile structures but only one TestvfsBuffer structure.
*/
class TestvfsBuffer {
public string zFile; /* Associated file name */
public int pgsz; /* Page size */
public u8[] aPage = new u8[TESTVFS_MAX_PAGES]; /* Array of ckalloc'd pages */
public TestvfsFd pFile; /* List of open handles */
public TestvfsBuffer pNext; /* Next in linked list of all buffers */
};
//#define PARENTVFS(x) (((Testvfs )((x)->pAppData))->pParent)
static sqlite3_vfs PARENTVFS( sqlite3_vfs x )
{
return ( (Testvfs)x.pAppData ).pParent;
}
//#define TESTVFS_MAX_ARGS 12
const int TESTVFS_MAX_ARGS =12;
/*
** Method declarations for TestvfsFile.
*/
//static int tvfsClose(sqlite3_file);
//static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
//static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
//static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size);
//static int tvfsSync(sqlite3_file*, int flags);
//static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
//static int tvfsLock(sqlite3_file*, int);
//static int tvfsUnlock(sqlite3_file*, int);
//static int tvfsCheckReservedLock(sqlite3_file*, int );
//static int tvfsFileControl(sqlite3_file*, int op, object *pArg);
//static int tvfsSectorSize(sqlite3_file);
//static int tvfsDeviceCharacteristics(sqlite3_file);
///*
//** Method declarations for tvfs_vfs.
//*/
//static int tvfsOpen(sqlite3_vfs*, string , sqlite3_file*, int , int );
//static int tvfsDelete(sqlite3_vfs*, string zName, int syncDir);
//static int tvfsAccess(sqlite3_vfs*, string zName, int flags, int );
//static int tvfsFullPathname(sqlite3_vfs*, string zName, int, string zOut);
//#if !SQLITE_OMIT_LOAD_EXTENSION
//static void tvfsDlOpen(sqlite3_vfs*, string zFilename);
//static void tvfsDlError(sqlite3_vfs*, int nByte, string zErrMsg);
//static void (*tvfsDlSym(sqlite3_vfs*,void*, string zSymbol))(void);
//static void tvfsDlClose(sqlite3_vfs*, void);
//#endif //* SQLITE_OMIT_LOAD_EXTENSION */
//static int tvfsRandomness(sqlite3_vfs*, int nByte, string zOut);
//static int tvfsSleep(sqlite3_vfs*, int microseconds);
//static int tvfsCurrentTime(sqlite3_vfs*, double);
//static int tvfsShmOpen(sqlite3_file);
//static int tvfsShmLock(sqlite3_file*, int , int, int);
//static int tvfsShmMap(sqlite3_file*,int,int,int, object volatile *);
//static void tvfsShmBarrier(sqlite3_file);
//static int tvfsShmUnmap(sqlite3_file*, int);
static sqlite3_io_methods tvfs_io_methods = new sqlite3_io_methods(
2, /* iVersion */
tvfsClose, /* xClose */
tvfsRead, /* xRead */
tvfsWrite, /* xWrite */
tvfsTruncate, /* xTruncate */
tvfsSync, /* xSync */
tvfsFileSize, /* xFileSize */
tvfsLock, /* xLock */
tvfsUnlock, /* xUnlock */
tvfsCheckReservedLock, /* xCheckReservedLock */
tvfsFileControl, /* xFileControl */
tvfsSectorSize, /* xSectorSize */
tvfsDeviceCharacteristics, /* xDeviceCharacteristics */
tvfsShmMap, /* xShmMap */
tvfsShmLock, /* xShmLock */
tvfsShmBarrier, /* xShmBarrier */
tvfsShmUnmap /* xShmUnmap */
);
class errcode {
public int eCode;
public string zCode;
public errcode(int eCode, string zCode){
this.eCode=eCode;this.zCode=zCode;
}
}
static int tvfsResultCode(Testvfs p, ref int pRc){
errcode[] aCode = new errcode[] {
new errcode( SQLITE_OK, "SQLITE_OK" ),
new errcode( SQLITE_ERROR, "SQLITE_ERROR" ),
new errcode( SQLITE_IOERR, "SQLITE_IOERR" ),
new errcode( SQLITE_LOCKED, "SQLITE_LOCKED" ),
new errcode( SQLITE_BUSY, "SQLITE_BUSY" )
};
string z;
int i;
z = TCL.Tcl_GetStringResult(p.interp);
for(i=0; i<ArraySize(aCode); i++){
if ( 0 == z.CompareTo( aCode[i].zCode ) )
{
pRc = aCode[i].eCode;
return 1;
}
}
return 0;
}
static int tvfsInjectFault(TestFaultInject p){
int ret = 0;
if ( p.eFault != 0 )
{
p.iCnt--;
if( p.iCnt==0 || (p.iCnt<0 && p.eFault==FAULT_INJECT_PERSISTENT ) ){
ret = 1;
p.nFail++;
}
}
return ret;
}
static int tvfsInjectIoerr(Testvfs p){
return tvfsInjectFault(p.ioerr_err);
}
static int tvfsInjectFullerr(Testvfs p){
return tvfsInjectFault(p.full_err);
}
static int tvfsInjectCantopenerr(Testvfs p){
return tvfsInjectFault(p.cantopen_err);
}
static void tvfsExecTcl(
Testvfs p,
string zMethod,
Tcl_Obj arg1,
Tcl_Obj arg2,
Tcl_Obj arg3
){
int rc; /* Return code from Tcl_EvalObj() */
Tcl_Obj pEval;
Debug.Assert( p.pScript!=null );
Debug.Assert( zMethod != null );
Debug.Assert( p != null );
Debug.Assert( arg2 == null || arg1 != null );
Debug.Assert( arg3 == null || arg2 != null );
pEval = TCL.Tcl_DuplicateObj(p.pScript);
TCL.Tcl_IncrRefCount(p.pScript);
TCL.Tcl_ListObjAppendElement( p.interp, pEval, TCL.Tcl_NewStringObj( zMethod, -1 ) );
if ( arg1!=null )
TCL.Tcl_ListObjAppendElement( p.interp, pEval, arg1 );
if ( arg2 !=null )
TCL.Tcl_ListObjAppendElement( p.interp, pEval, arg2 );
if ( arg3 != null )
TCL.Tcl_ListObjAppendElement( p.interp, pEval, arg3 );
rc = TCL.Tcl_EvalObjEx(p.interp, pEval, TCL.TCL_EVAL_GLOBAL);
if ( rc != TCL.TCL_OK )
{
TCL.Tcl_BackgroundError( p.interp );
TCL.Tcl_ResetResult( p.interp );
}
}
/*
** Close an tvfs-file.
*/
static int tvfsClose(sqlite3_file pFile){
int rc=0;
TestvfsFile pTestfile = (TestvfsFile )pFile;
TestvfsFd pFd = pTestfile.pFd;
Testvfs p = (Testvfs )pFd.pVfs.pAppData;
Debugger.Break(); //TODO
//if( p.pScript != null && (p.mask&TESTVFS_CLOSE_MASK)!=0 ){
// tvfsExecTcl(p, "xClose",
// Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId, 0
// );
//}
//if( pFd.pShmId != null){
// Tcl_DecrRefCount(pFd.pShmId);
// pFd.pShmId = null;
//}
//if ( pFile.pMethods != null )
//{
// ckfree((char )pFile.pMethods);
//}
//rc = sqlite3OsClose(pFd.pReal);
//ckfree((char )pFd);
//pTestfile.pFd = null;
return rc;
}
/*
** Read data from an tvfs-file.
*/
static int tvfsRead(
sqlite3_file pFile,
byte[] zBuf,
int iAmt,
sqlite_int64 iOfst
){
TestvfsFd p = tvfsGetFd(pFile);
return sqlite3OsRead(p.pReal, zBuf, iAmt, iOfst);
}
/*
** Write data to an tvfs-file.
*/
static int tvfsWrite(
sqlite3_file pFile,
byte[] zBuf,
int iAmt,
sqlite_int64 iOfst
){
int rc = SQLITE_OK;
Debugger.Break();//TODO
//TestvfsFd pFd = tvfsGetFd(pFile);
//Testvfs p = (Testvfs )pFd.pVfs.pAppData;
//if ( p.pScript != null && (p.mask & TESTVFS_WRITE_MASK) != 0 )
//{
// tvfsExecTcl(p, "xWrite",
// TCL.Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId, null
// );
// tvfsResultCode(p, ref rc);
//}
//if( rc==SQLITE_OK && tvfsInjectFullerr(p)!=0 ){
// rc = SQLITE_FULL;
//}
//if ( rc == SQLITE_OK && (p.mask & TESTVFS_WRITE_MASK) != 0 && tvfsInjectIoerr( p ) != 0 )
//{
// rc = SQLITE_IOERR;
//}
//if( rc==SQLITE_OK ){
// rc = sqlite3OsWrite(pFd.pReal, zBuf, iAmt, iOfst);
//}
return rc;
}
/*
** Truncate an tvfs-file.
*/
static int tvfsTruncate(sqlite3_file pFile, sqlite_int64 size){
int rc = SQLITE_OK;
TestvfsFd pFd = tvfsGetFd(pFile);
Testvfs p = (Testvfs )pFd.pVfs.pAppData;
if ( p.pScript != null && ( p.mask & TESTVFS_TRUNCATE_MASK ) != 0 )
{
tvfsExecTcl(p, "xTruncate",
TCL.Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId,null
);
tvfsResultCode(p, ref rc);
}
if( rc==SQLITE_OK ){
rc = sqlite3OsTruncate(pFd.pReal, size);
}
return rc;
}
/*
** Sync an tvfs-file.
*/
static int tvfsSync(sqlite3_file pFile, int flags){
int rc = SQLITE_OK;
TestvfsFd pFd = tvfsGetFd(pFile);
Testvfs p = (Testvfs )pFd.pVfs.pAppData;
if ( p.pScript != null && ( p.mask & TESTVFS_SYNC_MASK ) != 0 )
{
string zFlags = "";
switch( flags ){
case SQLITE_SYNC_NORMAL:
zFlags = "normal";
break;
case SQLITE_SYNC_FULL:
zFlags = "full";
break;
case SQLITE_SYNC_NORMAL|SQLITE_SYNC_DATAONLY:
zFlags = "normal|dataonly";
break;
case SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY:
zFlags = "full|dataonly";
break;
default:
Debug.Assert(false);
break;
}
tvfsExecTcl(p, "xSync",
TCL.Tcl_NewStringObj(pFd.zFilename, -1), pFd.pShmId,
TCL.Tcl_NewStringObj( zFlags, -1 )
);
tvfsResultCode(p, ref rc);
}
if( rc==SQLITE_OK && tvfsInjectFullerr(p)!=0 ) rc = SQLITE_FULL;
if( rc==SQLITE_OK ){
rc = sqlite3OsSync(pFd.pReal, flags);
}
return rc;
}
/*
** Return the current file-size of an tvfs-file.
*/
static int tvfsFileSize(sqlite3_file pFile, ref sqlite_int64 pSize){
TestvfsFd p = tvfsGetFd(pFile);
return sqlite3OsFileSize(p.pReal, ref pSize);
}
/*
** Lock an tvfs-file.
*/
static int tvfsLock(sqlite3_file pFile, int eLock){
TestvfsFd p = tvfsGetFd(pFile);
return sqlite3OsLock(p.pReal, eLock);
}
/*
** Unlock an tvfs-file.
*/
static int tvfsUnlock(sqlite3_file pFile, int eLock){
TestvfsFd p = tvfsGetFd(pFile);
return sqlite3OsUnlock(p.pReal, eLock);
}
/*
** Check if another file-handle holds a RESERVED lock on an tvfs-file.
*/
static int tvfsCheckReservedLock( sqlite3_file pFile, ref int pResOut )
{
TestvfsFd p = tvfsGetFd(pFile);
return sqlite3OsCheckReservedLock( p.pReal, ref pResOut );
}
/*
** File control method. For custom operations on an tvfs-file.
*/
static int tvfsFileControl( sqlite3_file pFile, int op, ref sqlite3_int64 pArg )
{
TestvfsFd p = tvfsGetFd(pFile);
return sqlite3OsFileControl( p.pReal, (u32)op, ref pArg );
}
/*
** Return the sector-size in bytes for an tvfs-file.
*/
static int tvfsSectorSize(sqlite3_file pFile){
TestvfsFd pFd = tvfsGetFd(pFile);
Testvfs p = (Testvfs )pFd.pVfs.pAppData;
if( p.iSectorsize>=0 ){
return p.iSectorsize;
}
return sqlite3OsSectorSize(pFd.pReal);
}
/*
** Return the device characteristic flags supported by an tvfs-file.
*/
static int tvfsDeviceCharacteristics(sqlite3_file pFile){
TestvfsFd pFd = tvfsGetFd(pFile);
Testvfs p = (Testvfs )pFd.pVfs.pAppData;
if( p.iDevchar>=0 ){
return p.iDevchar;
}
return sqlite3OsDeviceCharacteristics(pFd.pReal);
}
/*
** Open an tvfs file handle.
*/
static int tvfsOpen(
sqlite3_vfs pVfs,
string zName,
sqlite3_file pFile,
int flags,
ref int pOutFlags
){
int rc=0;
Debugger.Break();//TODO
//TestvfsFile pTestfile = (TestvfsFile)pFile;
//TestvfsFd pFd;
//Tcl_Obj pId = null;
//Testvfs p = (Testvfs )pVfs.pAppData;
//pFd = (TestvfsFd )ckalloc(sizeof(TestvfsFd) + PARENTVFS(pVfs).szOsFile);
//pFd = new TestvfsFd();// memset( pFd, 0, sizeof( TestvfsFd ) + PARENTVFS( pVfs ).szOsFile );
//pFd.pShm = null;
//pFd.pShmId = null;
//pFd.zFilename = zName;
//pFd.pVfs = pVfs;
//pFd.pReal = (sqlite3_file )pFd[1];
//pTestfile = new TestvfsFile();// memset( pTestfile, 0, sizeof( TestvfsFile ) );
//pTestfile.pFd = pFd;
///* Evaluate the Tcl script:
//**
//** SCRIPT xOpen FILENAME KEY-VALUE-ARGS
//**
//** If the script returns an SQLite error code other than SQLITE_OK, an
//** error is returned to the caller. If it returns SQLITE_OK, the new
//** connection is named "anon". Otherwise, the value returned by the
//** script is used as the connection name.
//*/
//TCL.Tcl_ResetResult(p.interp);
//if ( p.pScript != null && ( p.mask & TESTVFS_OPEN_MASK ) != 0 )
//{
// Tcl_Obj pArg = TCL.Tcl_NewObj();
// TCL.Tcl_IncrRefCount( pArg );
// if( (flags&SQLITE_OPEN_MAIN_DB )!=0){
// string z = zName[strlen(zName)+1];
// while( *z ){
// TCL.Tcl_ListObjAppendElement( 0, pArg, TCL.Tcl_NewStringObj( z, -1 ) );
// z += strlen(z) + 1;
// TCL.Tcl_ListObjAppendElement( 0, pArg, TCL.Tcl_NewStringObj( z, -1 ) );
// z += strlen(z) + 1;
// }
// }
// tvfsExecTcl(p, "xOpen", TCL.Tcl_NewStringObj(pFd.zFilename, -1), pArg, null);
// TCL.Tcl_DecrRefCount( pArg );
// if( tvfsResultCode(p, ref rc)!=0 ){
// if( rc!=SQLITE_OK ) return rc;
// }else{
// pId = TCL.Tcl_GetObjResult(p.interp);
// }
//}
//if( (p.mask&TESTVFS_OPEN_MASK)!=0 && tvfsInjectIoerr(p) !=0) return SQLITE_IOERR;
//if( tvfsInjectCantopenerr(p)!=0 ) return SQLITE_CANTOPEN;
//if( tvfsInjectFullerr(p)!=0 ) return SQLITE_FULL;
//if( null==pId ){
// pId = TCL.Tcl_NewStringObj("anon", -1);
//}
//TCL.Tcl_IncrRefCount( pId );
//pFd.pShmId = pId;
//TCL.Tcl_ResetResult( p.interp );
//rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, pFd.pReal, flags, pOutFlags);
//if ( pFd.pReal.pMethods != null )
//{
// sqlite3_io_methods pMethods;
// int nByte;
//if( pVfs.iVersion>1 ){
// nByte = sizeof(sqlite3_io_methods);
//}else{
// nByte = offsetof(sqlite3_io_methods, xShmMap);
//}
//pMethods = (sqlite3_io_methods)ckalloc( nByte );
//memcpy(pMethods, &tvfs_io_methods, nByte);
//pMethods.iVersion = pVfs.iVersion;
//if( pVfs.iVersion>1 && ((Testvfs )pVfs.pAppData).isNoshm ){
// pMethods.xShmUnmap = 0;
// pMethods.xShmLock = 0;
// pMethods.xShmBarrier = 0;
// pMethods.xShmMap = 0;
//}
// pFile.pMethods = pMethods;
//}
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 tvfsDelete(sqlite3_vfs pVfs, string zPath, int dirSync){
int rc = SQLITE_OK;
Testvfs p = (Testvfs )pVfs.pAppData;
if( p.pScript !=null && (p.mask&TESTVFS_DELETE_MASK)!=0 ){
tvfsExecTcl(p, "xDelete",
TCL.Tcl_NewStringObj( zPath, -1 ), TCL.Tcl_NewIntObj( dirSync ), null
);
tvfsResultCode(p, ref rc);
}
if( rc==SQLITE_OK ){
rc = sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);
}
return rc;
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int tvfsAccess(
sqlite3_vfs pVfs,
string zPath,
int flags,
ref int pResOut
){
Testvfs p = (Testvfs )pVfs.pAppData;
if ( p.pScript != null && ( p.mask & TESTVFS_ACCESS_MASK ) != 0 )
{
int rc=0;
string zArg = "";
if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS";
if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE";
if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ";
tvfsExecTcl(p, "xAccess",
TCL.Tcl_NewStringObj( zPath, -1 ), TCL.Tcl_NewStringObj( zArg, -1 ), null
);
if( tvfsResultCode(p, ref rc) !=0){
if( rc!=SQLITE_OK ) return rc;
}else{
Tcl_Interp interp = p.interp;
bool bTemp = false;
if ( !TCL.Tcl_GetBooleanFromObj( null, TCL.Tcl_GetObjResult( interp ), out bTemp ) )
{
pResOut = bTemp ? 1 : 0;
return SQLITE_OK;
}
}
}
return sqlite3OsAccess( PARENTVFS( pVfs ), zPath, flags, ref pResOut );
}
/*
** 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 (DEVSYM_MAX_PATHNAME+1) bytes.
*/
static int tvfsFullPathname(
sqlite3_vfs pVfs,
string zPath,
int nOut,
StringBuilder zOut
){
Testvfs p = (Testvfs )pVfs.pAppData;
if ( p.pScript != null && ( p.mask & TESTVFS_FULLPATHNAME_MASK ) != 0 )
{
int rc=0;
tvfsExecTcl(p, "xFullPathname", TCL.Tcl_NewStringObj(zPath, -1),null,null);
if( tvfsResultCode(p, ref rc) !=0){
if( rc!=SQLITE_OK ) return rc;
}
}
return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut);
}
#if !SQLITE_OMIT_LOAD_EXTENSION
/*
** Open the dynamic library located at zPath and return a handle.
*/
static IntPtr tvfsDlOpen(sqlite3_vfs pVfs, string zPath){
return sqlite3OsDlOpen(PARENTVFS(pVfs), 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 tvfsDlError(sqlite3_vfs pVfs, int nByte, string zErrMsg){
sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg);
}
/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void tvfsDlSym(sqlite3_vfs pVfs, IntPtr p, string zSym){
sqlite3OsDlSym(PARENTVFS(pVfs), p, ref zSym);
}
/*
** Close the dynamic library handle pHandle.
*/
static void tvfsDlClose( sqlite3_vfs pVfs, IntPtr pHandle )
{
sqlite3OsDlClose(PARENTVFS(pVfs), pHandle);
}
#endif //* SQLITE_OMIT_LOAD_EXTENSION */
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int tvfsRandomness(sqlite3_vfs pVfs, int nByte, byte[] zBufOut){
return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut);
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int tvfsSleep(sqlite3_vfs pVfs, int nMicro){
return sqlite3OsSleep(PARENTVFS(pVfs), nMicro);
}
/*
** Return the current time as a Julian Day number in pTimeOut.
*/
static int tvfsCurrentTime(sqlite3_vfs pVfs, double pTimeOut){
return PARENTVFS(pVfs).xCurrentTime(PARENTVFS(pVfs), ref pTimeOut);
}
static int tvfsShmOpen(sqlite3_file pFile){
Testvfs p;
int rc = SQLITE_OK; /* Return code */
Debugger.Break();//TODO
//TestvfsBuffer pBuffer; /* Buffer to open connection to */
//TestvfsFd pFd; /* The testvfs file structure */
//pFd = tvfsGetFd(pFile);
//p = (Testvfs )pFd.pVfs.pAppData;
//Debug.Assert( pFd.pShmId && pFd.pShm==null && pFd.pNext==null );
///* Evaluate the Tcl script:
//**
//** SCRIPT xShmOpen FILENAME
//*/
//TCL.Tcl_ResetResult(p.interp);
//if ( p.pScript != null && ( p.mask & TESTVFS_SHMOPEN_MASK ) != 0 )
//{
// tvfsExecTcl(p, "xShmOpen", TCL.Tcl_NewStringObj(pFd.zFilename, -1), 0, 0);
// if( tvfsResultCode(p, ref rc)!=0 ){
// if( rc!=SQLITE_OK ) return rc;
// }
//}
//Debug.Assert( rc==SQLITE_OK );
//if ( ( p.mask & TESTVFS_SHMOPEN_MASK ) != 0 && tvfsInjectIoerr( p ) )
//{
// return SQLITE_IOERR;
//}
///* Search for a TestvfsBuffer. Create a new one if required. */
//for(pBuffer=p.pBuffer; pBuffer!=null; pBuffer=pBuffer.pNext){
// if( 0==strcmp(pFd.zFilename, pBuffer.zFile) ) break;
//}
//if( null==pBuffer ){
// int nByte = sizeof(TestvfsBuffer) + strlen(pFd.zFilename) + 1;
// pBuffer = (TestvfsBuffer )ckalloc(nByte);
// memset(pBuffer, 0, nByte);
// pBuffer.zFile = (char )&pBuffer[1];
// strcpy(pBuffer.zFile, pFd.zFilename);
// pBuffer.pNext = p.pBuffer;
// p.pBuffer = pBuffer;
//}
///* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */
//pFd.pNext = pBuffer.pFile;
//pBuffer.pFile = pFd;
//pFd.pShm = pBuffer;
return SQLITE_OK;
}
static void tvfsAllocPage(TestvfsBuffer p, int iPage, int pgsz){
Debugger.Break();//TODO
//Debug.Assert( iPage < TESTVFS_MAX_PAGES );
//if( p.aPage[iPage]==0 ){
// p.aPage[iPage] = (u8 )ckalloc(pgsz);
// memset(p.aPage[iPage], 0, pgsz);
// p.pgsz = pgsz;
//}
}
static int tvfsShmMap(
sqlite3_file pFile, /* Handle open on database file */
int iPage, /* Page to retrieve */
int pgsz, /* Size of pages */
int isWrite, /* True to extend file if necessary */
out object pp /* OUT: Mapped memory */
){
int rc = SQLITE_OK;
Debugger.Break();//TODO
pp = null;
//TestvfsFd pFd = tvfsGetFd( pFile );
//Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
//if( 0==pFd.pShm ){
// rc = tvfsShmOpen(pFile);
// if( rc!=SQLITE_OK ){
// return rc;
// }
//}
//if( p.pScript != null && (p.mask&TESTVFS_SHMMAP_MASK )!=0){
// Tcl_Obj pArg = TCL.Tcl_NewObj();
// Tcl_IncrRefCount(pArg);
// Tcl_ListObjAppendElement(p.interp, pArg, TCL.Tcl_NewIntObj(iPage));
// Tcl_ListObjAppendElement(p.interp, pArg, TCL.Tcl_NewIntObj(pgsz));
// Tcl_ListObjAppendElement(p.interp, pArg, TCL.Tcl_NewIntObj(isWrite));
// tvfsExecTcl(p, "xShmMap",
// Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId, pArg
// );
// tvfsResultCode(p, ref rc);
// Tcl_DecrRefCount(pArg);
//}
//if( rc==SQLITE_OK && (p.mask&TESTVFS_SHMMAP_MASK )!=0&& tvfsInjectIoerr(p) ){
// rc = SQLITE_IOERR;
//}
//if( rc==SQLITE_OK && isWrite && !pFd.pShm.aPage[iPage] ){
// tvfsAllocPage(pFd.pShm, iPage, pgsz);
//}
//pp = pFd.pShm.aPage[iPage];
return rc;
}
static int tvfsShmLock(
sqlite3_file pFile,
int ofst,
int n,
int flags
){
int rc = SQLITE_OK;
Debugger.Break();//TODO
//TestvfsFd pFd = tvfsGetFd(pFile);
//Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
//int nLock;
//StringBuilder zLock =new StringBuilder(80);//char zLock[80];
//if( p.pScript !=null && (p.mask&TESTVFS_SHMLOCK_MASK)!=0 ){
// sqlite3_snprintf(sizeof(zLock), zLock, "%d %d", ofst, n);
// nLock = strlen(zLock);
// if( flags & SQLITE_SHM_LOCK ){
// strcpy(&zLock[nLock], " lock");
// }else{
// strcpy(&zLock[nLock], " unlock");
// }
// nLock += strlen(&zLock[nLock]);
// if( flags & SQLITE_SHM_SHARED ){
// strcpy(&zLock[nLock], " shared");
// }else{
// strcpy(&zLock[nLock], " exclusive");
// }
// tvfsExecTcl(p, "xShmLock",
// Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId,
// Tcl_NewStringObj(zLock, -1)
// );
// tvfsResultCode(p, ref rc);
//}
//if( rc==SQLITE_OK && (p.mask&TESTVFS_SHMLOCK_MASK )!=0&& tvfsInjectIoerr(p) ){
// rc = SQLITE_IOERR;
//}
//if( rc==SQLITE_OK ){
// int isLock = (flags & SQLITE_SHM_LOCK);
// int isExcl = (flags & SQLITE_SHM_EXCLUSIVE);
// u32 mask = (((1<<n)-1) << ofst);
// if( isLock ){
// TestvfsFd p2;
// for(p2=pFd.pShm.pFile; p2; p2=p2.pNext){
// if( p2==pFd ) continue;
// if( (p2.excllock&mask) || (isExcl && p2.sharedlock&mask) ){
// rc = SQLITE_BUSY;
// break;
// }
// }
// if( rc==SQLITE_OK ){
// if( isExcl ) pFd.excllock |= mask;
// if( null==isExcl ) pFd.sharedlock |= mask;
// }
// }else{
// if( isExcl ) pFd.excllock &= (~mask);
// if( null==isExcl ) pFd.sharedlock &= (~mask);
// }
//}
return rc;
}
static void tvfsShmBarrier(sqlite3_file pFile){
Debugger.Break();//TODO
//TestvfsFd pFd = tvfsGetFd(pFile);
//Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
//if ( p.pScript != null && ( p.mask & TESTVFS_SHMBARRIER_MASK ) != 0 )
//{
// tvfsExecTcl(p, "xShmBarrier",
// Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId, 0
// );
//}
}
static int tvfsShmUnmap(
sqlite3_file pFile,
int deleteFlag
){
int rc = SQLITE_OK;
Debugger.Break();//TODO
//TestvfsFd pFd = tvfsGetFd( pFile );
//Testvfs p = (Testvfs )(pFd.pVfs.pAppData);
//TestvfsBuffer pBuffer = pFd.pShm;
//TestvfsFd ppFd;
//if( null==pBuffer ) return SQLITE_OK;
//Debug.Assert( pFd.pShmId && pFd.pShm );
//if ( p.pScript != null && ( p.mask & TESTVFS_SHMCLOSE_MASK ) != 0 )
//{
// tvfsExecTcl(p, "xShmUnmap",
// Tcl_NewStringObj(pFd.pShm.zFile, -1), pFd.pShmId, 0
// );
// tvfsResultCode(p, ref rc);
//}
//for(ppFd=pBuffer.pFile; ppFd!=pFd; ppFd=&((ppFd).pNext));
//Debug.Assert( (ppFd)==pFd );
//ppFd = pFd.pNext;
//pFd.pNext = 0;
//if( pBuffer.pFile==null ){
// int i;
// TestvfsBuffer pp;
// for(pp=p.pBuffer; pp!=pBuffer; pp=((pp).pNext));
// pp = (pp).pNext;
// Debugger.Break();//TODO
// //for(i=0; pBuffer.aPage[i]!= null; i++){
// // ckfree((char )pBuffer.aPage[i]);
// //}
// //ckfree((char )pBuffer);
//}
//pFd.pShm = null;
return rc;
}
enum DB_enum_CMD {
CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT,
CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR, CMD_CANTOPENERR
};
class TestvfsSubcmd {
public string zName;
public DB_enum_CMD eCmd;
public TestvfsSubcmd (string zName, DB_enum_CMD eCmd){this.zName=zName;this.eCmd=eCmd;}
}
class VfsMethod {
public string zName;
public int mask;
public VfsMethod (string zName, int mask){this.zName=zName;this.mask=mask;}
}
class DeviceFlag {
public string zName;
public int iValue;
public DeviceFlag (string zName, int iValue){this.zName=zName;this.iValue=iValue;}
}
class _aFlag
{
public string zName;
public int iValue;
public _aFlag( string zName, int iValue )
{
this.zName = zName;
this.iValue = iValue;
}
}
static int testvfs_obj_cmd(
ClientData cd,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
){
Debugger.Break();//TODO
// Testvfs p = (Testvfs)cd;
// TestvfsSubcmd[] aSubcmd = new TestvfsSubcmd[] {
// new TestvfsSubcmd( "shm", DB_enum_CMD.CMD_SHM ),
// new TestvfsSubcmd( "delete", DB_enum_CMD.CMD_DELETE ),
// new TestvfsSubcmd( "filter", DB_enum_CMD.CMD_FILTER ),
// new TestvfsSubcmd( "ioerr", DB_enum_CMD.CMD_IOERR ),
// new TestvfsSubcmd( "fullerr", DB_enum_CMD.CMD_FULLERR ),
// new TestvfsSubcmd( "cantopenerr", DB_enum_CMD.CMD_CANTOPENERR ),
// new TestvfsSubcmd( "script", DB_enum_CMD.CMD_SCRIPT ),
// new TestvfsSubcmd( "devchar", DB_enum_CMD.CMD_DEVCHAR ),
// new TestvfsSubcmd( "sectorsize", DB_enum_CMD.CMD_SECTORSIZE ),
// new TestvfsSubcmd( 0, 0 )
// };
// int i=0;
// if( objc<2 ){
// TCL.Tcl_WrongNumArgs( interp, 1, objv, "SUBCOMMAND ..." );
// return TCL.TCL_ERROR;
// }
// if ( TCL.Tcl_GetIndexFromObjStruct(
// interp, objv[1], aSubcmd, aSubcmd.Length, "subcommand", 0, ref i)
// ){
// return TCL.TCL_ERROR;
// }
// TCL.Tcl_ResetResult( interp );
// switch( aSubcmd[i].eCmd ){
// case DB_enum_CMD.CMD_SHM: {
// Tcl_Obj pObj;
// int i;
// TestvfsBuffer pBuffer;
// string zName;
// if( objc!=3 && objc!=4 ){
// TCL.Tcl_WrongNumArgs( interp, 2, objv, "FILE ?VALUE?" );
// return TCL.TCL_ERROR;
// }
// zName = ckalloc(p.pParent.mxPathname);
// p.pParent.xFullPathname(
// p.pParent, TCL.Tcl_GetString(objv[2]),
// p.pParent.mxPathname, zName
// );
// for(pBuffer=p.pBuffer; pBuffer; pBuffer=pBuffer.pNext){
// if( 0==strcmp(pBuffer.zFile, zName) ) break;
// }
// ckfree(zName);
// if( null==pBuffer ){
// TCL.Tcl_AppendResult( interp, "no such file: ", TCL.Tcl_GetString( objv[2] ), 0 );
// return TCL.TCL_ERROR;
// }
// if( objc==4 ){
// int n;
// u8 *a = TCL.Tcl_GetByteArrayFromObj(objv[3], &n);
// int pgsz = pBuffer.pgsz;
// if( pgsz==0 ) pgsz = 65536;
// for(i=0; ipgsz<n; i++){
// int nByte = pgsz;
// tvfsAllocPage(pBuffer, i, pgsz);
// if( n-ipgsz<pgsz ){
// nByte = n;
// }
// memcpy(pBuffer.aPage[i], &a[ipgsz], nByte);
// }
// }
// pObj = TCL.Tcl_NewObj();
// for(i=0; pBuffer.aPage[i]!=null; i++){
// int pgsz = pBuffer.pgsz;
// if( pgsz==0 ) pgsz = 65536;
// TCL.Tcl_AppendObjToObj(pObj, TCL.Tcl_NewByteArrayObj(pBuffer.aPage[i], pgsz));
// }
// TCL.Tcl_SetObjResult( interp, pObj );
// break;
// }
// case DB_enum_CMD.CMD_FILTER: {
//VfsMethod[] vfsmethod = new VfsMethod[] {
// new VfsMethod( "xShmOpen", TESTVFS_SHMOPEN_MASK ),
// new VfsMethod( "xShmLock", TESTVFS_SHMLOCK_MASK ),
// new VfsMethod( "xShmBarrier", TESTVFS_SHMBARRIER_MASK ),
// new VfsMethod( "xShmUnmap", TESTVFS_SHMCLOSE_MASK ),
// new VfsMethod( "xShmMap", TESTVFS_SHMMAP_MASK ),
// new VfsMethod( "xSync", TESTVFS_SYNC_MASK ),
// new VfsMethod( "xDelete", TESTVFS_DELETE_MASK ),
// new VfsMethod( "xWrite", TESTVFS_WRITE_MASK ),
// new VfsMethod( "xTruncate", TESTVFS_TRUNCATE_MASK ),
// new VfsMethod( "xOpen", TESTVFS_OPEN_MASK ),
// new VfsMethod( "xClose", TESTVFS_CLOSE_MASK ),
// new VfsMethod( "xAccess", TESTVFS_ACCESS_MASK ),
// new VfsMethod( "xFullPathname", TESTVFS_FULLPATHNAME_MASK ),
//};
// Tcl_Obj[] apElem = null;
// int nElem = 0;
// int i;
// int mask = 0;
// if( objc!=3 ){
// TCL.Tcl_WrongNumArgs( interp, 2, objv, "LIST" );
// return TCL.TCL_ERROR;
// }
// if ( TCL.Tcl_ListObjGetElements( interp, objv[2], ref nElem, ref apElem ) )
// {
// return TCL.TCL_ERROR;
// }
// TCL.Tcl_ResetResult( interp );
// for(i=0; i<nElem; i++){
// int iMethod;
// string zElem = TCL.Tcl_GetString(apElem[i]);
// for(iMethod=0; iMethod<ArraySize(vfsmethod); iMethod++){
// if( strcmp(zElem, vfsmethod[iMethod].zName)==0 ){
// mask |= vfsmethod[iMethod].mask;
// break;
// }
// }
// if( iMethod==ArraySize(vfsmethod) ){
// TCL.Tcl_AppendResult( interp, "unknown method: ", zElem, 0 );
// return TCL.TCL_ERROR;
// }
// }
// p.mask = mask;
// break;
// }
// case DB_enum_CMD.CMD_SCRIPT: {
// if( objc==3 ){
// int nByte;
// if( p.pScript !=null){
// TCL.Tcl_DecrRefCount( p.pScript );
// p.pScript = 0;
// }
// TCL.Tcl_GetStringFromObj( objv[2], &nByte );
// if( nByte>0 ){
// p.pScript = TCL.Tcl_DuplicateObj(objv[2]);
// TCL.Tcl_IncrRefCount( p.pScript );
// }
// }else if( objc!=2 ){
// TCL.Tcl_WrongNumArgs( interp, 2, objv, "?SCRIPT?" );
// return TCL.TCL_ERROR;
// }
// TCL.Tcl_ResetResult( interp );
// if( p.pScript !=null) if( p.pScript )TCL.Tcl_SetObjResult(interp, p.pScript);
// break;
// }
// /*
// ** TESTVFS ioerr ?IFAIL PERSIST?
// **
// ** Where IFAIL is an integer and PERSIST is boolean.
// */
// case DB_enum_CMD.CMD_CANTOPENERR:
// case DB_enum_CMD.CMD_IOERR:
// case DB_enum_CMD.CMD_FULLERR: {
// TestFaultInject pTest;
// int iRet;
// switch( aSubcmd[i].eCmd ){
// case DB_enum_CMD.CMD_IOERR: pTest = p.ioerr_err; break;
// case DB_enum_CMD.CMD_FULLERR: pTest = p.full_err; break;
// case DB_enum_CMD.CMD_CANTOPENERR: pTest = p.cantopen_err; break;
// default: Debug.Assert(false);
// }
// iRet = pTest.nFail;
// pTest.nFail = 0;
// pTest.eFault = 0;
// pTest.iCnt = 0;
// if( objc==4 ){
// int iCnt, iPersist;
// if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], &iCnt )
// || TCL.TCL_OK != TCL.Tcl_GetBooleanFromObj( interp, objv[3], &iPersist )
// ){
// return TCL.TCL_ERROR;
// }
// pTest.eFault = iPersist != 0 ? FAULT_INJECT_PERSISTENT : FAULT_INJECT_TRANSIENT;
// pTest.iCnt = iCnt;
// }else if( objc!=2 ){
// TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CNT PERSIST?" );
// return TCL.TCL_ERROR;
// }
// TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( iRet ) );
// break;
// }
// case DB_enum_CMD.CMD_DELETE: {
// TCL.Tcl_DeleteCommand( interp, TCL.Tcl_GetString( objv[0] ) );
// break;
// }
// case DB_enum_CMD.CMD_DEVCHAR: {
//_aFlag[] aFlag = new _aFlag[] {
// new _aFlag( "default", -1 ),
// new _aFlag( "atomic", SQLITE_IOCAP_ATOMIC ),
// new _aFlag( "atomic512", SQLITE_IOCAP_ATOMIC512 ),
// new _aFlag( "atomic1k", SQLITE_IOCAP_ATOMIC1K ),
// new _aFlag( "atomic2k", SQLITE_IOCAP_ATOMIC2K ),
// new _aFlag( "atomic4k", SQLITE_IOCAP_ATOMIC4K ),
// new _aFlag( "atomic8k", SQLITE_IOCAP_ATOMIC8K ),
// new _aFlag( "atomic16k", SQLITE_IOCAP_ATOMIC16K ),
// new _aFlag( "atomic32k", SQLITE_IOCAP_ATOMIC32K ),
// new _aFlag( "atomic64k", SQLITE_IOCAP_ATOMIC64K ),
// new _aFlag( "sequential", SQLITE_IOCAP_SEQUENTIAL ),
// new _aFlag( "safe_append", SQLITE_IOCAP_SAFE_APPEND ),
// new _aFlag( "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN ),
// new _aFlag( 0, 0 )
// };
// Tcl_Obj pRet;
// int iFlag;
// if( objc>3 ){
// Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?");
// return TCL.TCL_ERROR;
// }
// if( objc==3 ){
// int j;
// int iNew = 0;
// Tcl_Obj[] flags = null;
// int nFlags = 0;
// if ( TCL.Tcl_ListObjGetElements( interp, objv[2], ref nFlags, ref flags ) )
// {
// return TCL.TCL_ERROR;
// }
// for(j=0; j<nFlags; j++){
// int idx = 0;
// if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag,
// aFlag.Length, "flag", 0, ref idx)
// ){
// return TCL.TCL_ERROR;
// }
// if( aFlag[idx].iValue<0 && nFlags>1 ){
// TCL.Tcl_AppendResult( interp, "bad flags: ", TCL.Tcl_GetString( objv[2] ), 0 );
// return TCL.TCL_ERROR;
// }
// iNew |= aFlag[idx].iValue;
// }
// p.iDevchar = iNew;
// }
// pRet = TCL.Tcl_NewObj();
// for(iFlag=0; iFlag<aFlag.Length ; iFlag++)//sizeof(aFlag)/sizeof(aFlag[0]); iFlag++)
// {
// if( p.iDevchar & aFlag[iFlag].iValue ){
// TCL.Tcl_ListObjAppendElement(
// interp, pRet, TCL.Tcl_NewStringObj(aFlag[iFlag].zName, -1)
// );
// }
// }
// TCL.Tcl_SetObjResult( interp, pRet );
// break;
// }
// case DB_enum_CMD.CMD_SECTORSIZE: {
// if( objc>3 ){
// TCL.Tcl_WrongNumArgs( interp, 2, objv, "?VALUE?" );
// return TCL.TCL_ERROR;
// }
// if( objc==3 ){
// int iNew = 0;
// if( Tcl_GetIntFromObj(interp, objv[2], ref iNew) ){
// return TCL.TCL_ERROR;
// }
// p.iSectorsize = iNew;
// }
// TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( p.iSectorsize ) );
// break;
// }
// }
return TCL.TCL_OK;
}
static void testvfs_obj_del(ClientData cd){
Testvfs p = (Testvfs)cd;
if ( p.pScript !=null)
TCL.Tcl_DecrRefCount( ref p.pScript );
sqlite3_vfs_unregister(p.pVfs);
Debugger.Break();//TODO
//ckfree((char )p.pVfs);
//ckfree((char )p);
}
/*
** Usage: testvfs VFSNAME ?SWITCHES?
**
** Switches are:
**
** -noshm BOOLEAN (True to omit shm methods. Default false)
** -default BOOLEAN (True to make the vfs default. Default false)
**
** This command creates two things when it is invoked: an SQLite VFS, and
** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not
** installed as the default VFS.
**
** The VFS passes all file I/O calls through to the underlying VFS.
**
** Whenever the xShmMap method of the VFS
** is invoked, the SCRIPT is executed as follows:
**
** SCRIPT xShmMap FILENAME ID
**
** The value returned by the invocation of SCRIPT above is interpreted as
** an SQLite error code and returned to SQLite. Either a symbolic
** "SQLITE_OK" or numeric "0" value may be returned.
**
** The contents of the shared-memory buffer associated with a given file
** may be read and set using the following command:
**
** VFSNAME shm FILENAME ?NEWVALUE?
**
** When the xShmLock method is invoked by SQLite, the following script is
** run:
**
** SCRIPT xShmLock FILENAME ID LOCK
**
** where LOCK is of the form "OFFSET NBYTE lock/unlock shared/exclusive"
*/
static int testvfs_cmd(
ClientData cd,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
){
Debugger.Break();//TODO
// sqlite3_vfs tvfs_vfs = new sqlite3_vfs(
// 2, /* iVersion */
// 0, /* szOsFile */
// 0, /* mxPathname */
// null, /* pNext */
// null, /* zName */
// 0, /* pAppData */
// tvfsOpen, /* xOpen */
// tvfsDelete, /* xDelete */
// tvfsAccess, /* xAccess */
// tvfsFullPathname, /* xFullPathname */
//#if !SQLITE_OMIT_LOAD_EXTENSION
// tvfsDlOpen, /* xDlOpen */
// tvfsDlError, /* xDlError */
// tvfsDlSym, /* xDlSym */
// tvfsDlClose, /* xDlClose */
//#else
// null, /* xDlOpen */
// null, /* xDlError */
// null, /* xDlSym */
// null, /* xDlClose */
//#endif //* SQLITE_OMIT_LOAD_EXTENSION */
// tvfsRandomness, /* xRandomness */
// tvfsSleep, /* xSleep */
// tvfsCurrentTime, /* xCurrentTime */
// null, /* xGetLastError */
// null, /* xCurrentTimeInt64 */
// null, null, null
// );
// Testvfs p; /* New object */
// sqlite3_vfs pVfs; /* New VFS */
// string zVfs;
// int nByte; /* Bytes of space to allocate at p */
// int i;
// int isNoshm = 0; /* True if -noshm is passed */
// int isDefault = 0; /* True if -default is passed */
// int szOsFile = 0; /* Value passed to -szosfile */
// int mxPathname = -1; /* Value passed to -mxpathname */
// int iVersion = 2; /* Value passed to -iversion */
// if( objc<2 || 0!=(objc%2) ) goto bad_args;
// for(i=2; i<objc; i += 2){
// int nSwitch;
// string zSwitch;
// zSwitch = TCL.Tcl_GetStringFromObj(objv[i], &nSwitch);
// if( nSwitch>2 && 0==strncmp("-noshm", zSwitch, nSwitch) ){
// if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], &isNoshm ) )
// {
// return TCL.TCL_ERROR;
// }
// }
// else if( nSwitch>2 && 0==strncmp("-default", zSwitch, nSwitch) ){
// if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], &isDefault ) )
// {
// return TCL.TCL_ERROR;
// }
// }
// else if( nSwitch>2 && 0==strncmp("-szosfile", zSwitch, nSwitch) ){
// if ( TCL.Tcl_GetIntFromObj( interp, objv[i + 1], &szOsFile ) )
// {
// return TCL.TCL_ERROR;
// }
// }
// else if( nSwitch>2 && 0==strncmp("-mxpathname", zSwitch, nSwitch) ){
// if ( TCL.Tcl_GetIntFromObj( interp, objv[i + 1], &mxPathname ) )
// {
// return TCL.TCL_ERROR;
// }
// }
// else if( nSwitch>2 && 0==strncmp("-iversion", zSwitch, nSwitch) ){
// if ( TCL.Tcl_GetIntFromObj( interp, objv[i + 1], &iVersion ) )
// {
// return TCL.TCL_ERROR;
// }
// }
// else{
// goto bad_args;
// }
// }
// if( szOsFile<sizeof(TestvfsFile) ){
// szOsFile = sizeof(TestvfsFile);
// }
// zVfs = TCL.Tcl_GetString(objv[1]);
// nByte = sizeof(Testvfs) + strlen(zVfs)+1;
// p = (Testvfs )ckalloc(nByte);
// memset(p, 0, nByte);
// p.iDevchar = -1;
// p.iSectorsize = -1;
// /* Create the new object command before querying SQLite for a default VFS
// ** to use for 'real' IO operations. This is because creating the new VFS
// ** may delete an existing [testvfs] VFS of the same name. If such a VFS
// ** is currently the default, the new [testvfs] may end up calling the
// ** methods of a deleted object.
// */
// TCL.Tcl_CreateObjCommand( interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del );
// p.pParent = sqlite3_vfs_find("");
// p.interp = interp;
// p.zName = (char )&p[1];
// memcpy(p.zName, zVfs, strlen(zVfs)+1);
// pVfs = new sqlite3_vfs();//(sqlite3_vfs )ckalloc(sizeof(sqlite3_vfs));
// tvfs_vfs.CopyTo(pVfs);//memcpy( pVfs, &tvfs_vfs, sizeof( sqlite3_vfs ) );
// pVfs.pAppData = p;
// pVfs.iVersion = iVersion;
// pVfs.zName = p.zName;
// pVfs.mxPathname = p.pParent.mxPathname;
// if( mxPathname>=0 && mxPathname<pVfs.mxPathname ){
// pVfs.mxPathname = mxPathname;
// }
// pVfs.szOsFile = szOsFile;
// p.pVfs = pVfs;
// p.isNoshm = isNoshm;
// p.mask = TESTVFS_ALL_MASK;
// sqlite3_vfs_register(pVfs, isDefault);
// return TCL.TCL_OK;
// bad_args:
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
return TCL.TCL_ERROR;
}
static int Sqlitetestvfs_Init(Tcl_Interp interp){
TCL.Tcl_CreateObjCommand( interp, "testvfs", testvfs_cmd, null, null );
return TCL.TCL_OK;
}
#endif
}
#endif
}