wasCSharpSQLite

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 1  →  ?path2? @ 4
/trunk/testfixture/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
 
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle( "TextFixture for C#-SQLite" )]
[assembly: AssemblyDescription( "Test Harness to run all the TCL tests" )]
[assembly: AssemblyConfiguration( "" )]
[assembly: AssemblyCompany( "Pioneer Software Consulting" )]
[assembly: AssemblyProduct( "Textfixture" )]
[assembly: AssemblyCopyright( "Copyright © 2010" )]
[assembly: AssemblyTrademark( "" )]
[assembly: AssemblyCulture( "" )]
 
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible( false )]
 
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid( "8dcf593a-8e11-4b78-a322-2162ed7cec11" )]
 
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion( "3.7.7.1" )]
[assembly: AssemblyFileVersion( "1.0.0.0" )]
/trunk/testfixture/app.config
@@ -0,0 +1,3 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
/trunk/testfixture/src/tclsqlite_c.cs
@@ -0,0 +1,4427 @@
using System;
using System.Diagnostics;
using sqlite_int64 = System.Int64;
using sqlite_u3264 = System.UInt64;
using u32 = System.UInt32;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using ClientData = System.Object;
 
#if !SQLITE_OMIT_INCRBLOB
using sqlite3_blob = sqlite.Incrblob;
#endif
using sqlite3_stmt = Sqlite3.Vdbe;
using Tcl_DString = tcl.lang.TclString;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using Tcl_WideInt = System.Int64;
 
using sqlite3_value = Sqlite3.Mem;
using System.IO;
using System.Text;
 
public partial class Sqlite3
{
/*
** 2001 September 15
**
** 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.
**
*************************************************************************
** A TCL Interface to SQLite. Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
** Compile-time options:
**
** -DTCLSH=1 Add a "main()" routine that works as a tclsh.
**
** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add
** four new commands to the TCL interpreter for
** generating MD5 checksums: md5, md5file,
** md5-10x8, and md5file-10x8.
**
** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add
** hundreds of new commands used for testing
** SQLite. This option implies -DSQLITE_TCLMD5.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
//#include "tcl.h"
//#include <errno.h>
 
/*
** Some additional include files are needed if this file is not
** appended to the amalgamation.
*/
#if !SQLITE_AMALGAMATION
//# include "sqlite3.h"
//# include <stdlib.h>
//# include <string.h>
//# include <Debug.Assert.h>
// typedef unsigned char u8;
#endif
 
/*
* Windows needs to know which symbols to export. Unix does not.
* BUILD_sqlite should be undefined for Unix.
*/
#if BUILD_sqlite
//#undef TCL.Tcl_STORAGE_CLASS
//#define TCL.Tcl_STORAGE_CLASS DLLEXPORT
#endif // * BUILD_sqlite */
 
const int NUM_PREPARED_STMTS = 10;//#define NUM_PREPARED_STMTS 10
const int MAX_PREPARED_STMTS = 100;//#define MAX_PREPARED_STMTS 100
 
/*
** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
** have to do a translation when going between the two. Set the
** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
** this translation.
*/
#if Tcl_UTF_MAX && !SQLITE_UTF8
//# define UTF_TRANSLATION_NEEDED 1
#endif
 
/*
** New SQL functions can be created as TCL scripts. Each such function
** is described by an instance of the following structure.
*/
//typedef struct SqlFunc SqlFunc;
public class SqlFunc
{
public Tcl_Interp interp; /* The TCL interpret to execute the function */
public Tcl_Obj pScript; /* The Tcl_Obj representation of the script */
public int useEvalObjv; /* True if it is safe to use TCL.Tcl_EvalObjv */
public string zName; /* Name of this function */
public SqlFunc pNext; /* Next function on the list of them all */
}
 
/*
** New collation sequences function can be created as TCL scripts. Each such
** function is described by an instance of the following structure.
*/
//typedef struct SqlCollate SqlCollate;
public class SqlCollate
{
public Tcl_Interp interp; /* The TCL interpret to execute the function */
public string zScript; /* The script to be run */
public SqlCollate pNext; /* Next function on the list of them all */
}
 
/*
** Prepared statements are cached for faster execution. Each prepared
** statement is described by an instance of the following structure.
*/
//typedef struct SqlPreparedStmt SqlPreparedStmt;
public class SqlPreparedStmt
{
public SqlPreparedStmt pNext; /* Next in linked list */
public SqlPreparedStmt pPrev; /* Previous on the list */
public sqlite3_stmt pStmt; /* The prepared statement */
public Mem[] aMem; /* Original Memory Values to be reused */
public int nSql; /* chars in zSql[] */
public string zSql; /* Text of the SQL statement */
public int nParm; /* Size of apParm array */
public Tcl_Obj[] apParm; /* Array of referenced object pointers */
}
 
//typedef struct IncrblobChannel IncrblobChannel;
 
/*
** There is one instance of this structure for each SQLite database
** that has been opened by the SQLite TCL interface.
*/
//typedef struct SqliteDb SqliteDb;
public class SqliteDb : object
{
public sqlite3 db; /* The "real" database structure. MUST BE FIRST */
public Tcl_Interp interp; /* The interpreter used for this database */
public string zBusy; /* The busy callback routine */
public string zCommit; /* The commit hook callback routine */
public string zTrace; /* The trace callback routine */
public string zProfile; /* The profile callback routine */
public string zProgress; /* The progress callback routine */
public string zAuth; /* The authorization callback routine */
public int disableAuth; /* Disable the authorizer if it exists */
public string zNull = ""; /* Text to substitute for an SQL NULL value */
public SqlFunc pFunc; /* List of SQL functions */
public Tcl_Obj pUpdateHook; /* Update hook script (if any) */
public Tcl_Obj pRollbackHook; /* Rollback hook script (if any) */
public Tcl_Obj pWalHook; /* WAL hook script (if any) */
public Tcl_Obj pUnlockNotify; /* Unlock notify script (if any) */
public SqlCollate pCollate; /* List of SQL collation functions */
public int rc; /* Return code of most recent sqlite3_exec() */
public Tcl_Obj pCollateNeeded; /* Collation needed script */
public SqlPreparedStmt stmtList; /* List of prepared statements*/
public SqlPreparedStmt stmtLast; /* Last statement in the list */
public int maxStmt; /* The next maximum number of stmtList */
public int nStmt; /* Number of statements in stmtList */
#if !SQLITE_OMIT_INCRBLOB
public IncrblobChannel pIncrblob; /* Linked list of open incrblob channels */
#endif
public int nStep, nSort, nIndex; /* Statistics for most recent operation */
public int nTransaction; /* Number of nested [transaction] methods */
}
 
#if !SQLITE_OMIT_INCRBLOB
class IncrblobChannel
{
public sqlite3_blob pBlob; /* sqlite3 blob handle */
public SqliteDb pDb; /* Associated database connection */
public int iSeek; /* Current seek offset */
public Tcl_Channel channel; /* Channel identifier */
public IncrblobChannel pNext; /* Linked list of all open incrblob channels */
public IncrblobChannel pPrev; /* Linked list of all open incrblob channels */
}
#endif
 
 
/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
*/
static int strlen30( StringBuilder z )
{
//string z2 = z;
//while( *z2 ){ z2++; }
return 0x3fffffff & z.Length;
}
 
static int strlen30( string z )
{
//string z2 = z;
//while( *z2 ){ z2++; }
return 0x3fffffff & z.Length;
}
 
 
#if !SQLITE_OMIT_INCRBLOB
/*
** Close all incrblob channels opened using database connection pDb.
** This is called when shutting down the database connection.
*/
static void closeIncrblobChannels( SqliteDb pDb )
{
IncrblobChannel p;
IncrblobChannel pNext;
 
for ( p = pDb.pIncrblob ; p != null ; p = pNext )
{
pNext = p.pNext;
 
/* Note: Calling unregister here call TCL.Tcl_Close on the incrblob channel,
** which deletes the IncrblobChannel structure at p. So do not
** call TCL.Tcl_Free() here.
*/
TCL.Tcl_UnregisterChannel( pDb.interp, p.channel );
}
}
 
/*
** Close an incremental blob channel.
*/
//static int incrblobClose(object instanceData, Tcl_Interp interp){
// IncrblobChannel p = (IncrblobChannel )instanceData;
// int rc = sqlite3_blob_close(p.pBlob);
// sqlite3 db = p.pDb.db;
 
// /* Remove the channel from the SqliteDb.pIncrblob list. */
// if( p.pNext ){
// p.pNext.pPrev = p.pPrev;
// }
// if( p.pPrev ){
// p.pPrev.pNext = p.pNext;
// }
// if( p.pDb.pIncrblob==p ){
// p.pDb.pIncrblob = p.pNext;
// }
 
// /* Free the IncrblobChannel structure */
// TCL.Tcl_Free((char )p);
 
// if( rc!=SQLITE_OK ){
// TCL.Tcl_SetResult(interp, (char )sqlite3_errmsg(db), TCL.Tcl_VOLATILE);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
 
/*
** Read data from an incremental blob channel.
*/
//static int incrblobInput(
// object instanceData,
// char *buf,
// int bufSize,
// int *errorCodePtr
//){
// IncrblobChannel p = (IncrblobChannel )instanceData;
// int nRead = bufSize; /* Number of bytes to read */
// int nBlob; /* Total size of the blob */
// int rc; /* sqlite error code */
 
// nBlob = sqlite3_blob_bytes(p.pBlob);
// if( (p.iSeek+nRead)>nBlob ){
// nRead = nBlob-p.iSeek;
// }
// if( nRead<=0 ){
// return 0;
// }
 
// rc = sqlite3_blob_read(p.pBlob, (void )buf, nRead, p.iSeek);
// if( rc!=SQLITE_OK ){
// *errorCodePtr = rc;
// return -1;
// }
 
// p.iSeek += nRead;
// return nRead;
//}
 
/*
** Write data to an incremental blob channel.
*/
//static int incrblobOutput(
// object instanceData,
// string buf,
// int toWrite,
// int *errorCodePtr
//){
// IncrblobChannel p = (IncrblobChannel )instanceData;
// int nWrite = toWrite; /* Number of bytes to write */
// int nBlob; /* Total size of the blob */
// int rc; /* sqlite error code */
 
// nBlob = sqlite3_blob_bytes(p.pBlob);
// if( (p.iSeek+nWrite)>nBlob ){
// *errorCodePtr = EINVAL;
// return -1;
// }
// if( nWrite<=0 ){
// return 0;
// }
 
// rc = sqlite3_blob_write(p.pBlob, (void )buf, nWrite, p.iSeek);
// if( rc!=SQLITE_OK ){
// *errorCodePtr = EIO;
// return -1;
// }
 
// p.iSeek += nWrite;
// return nWrite;
//}
 
/*
** Seek an incremental blob channel.
*/
//static int incrblobSeek(
// object instanceData,
// long offset,
// int seekMode,
// int *errorCodePtr
//){
// IncrblobChannel p = (IncrblobChannel )instanceData;
 
// switch( seekMode ){
// case SEEK_SET:
// p.iSeek = offset;
// break;
// case SEEK_CUR:
// p.iSeek += offset;
// break;
// case SEEK_END:
// p.iSeek = sqlite3_blob_bytes(p.pBlob) + offset;
// break;
 
// default: Debug.Assert(!"Bad seekMode");
// }
 
// return p.iSeek;
//}
 
 
//static void incrblobWatch(object instanceData, int mode){
// /* NO-OP */
//}
//static int incrblobHandle(object instanceData, int dir, object *hPtr){
// return TCL.TCL_ERROR;
//}
 
static TCL.Tcl_ChannelType IncrblobChannelType = {
"incrblob", /* typeName */
TCL.Tcl_CHANNEL_VERSION_2, /* version */
incrblobClose, /* closeProc */
incrblobInput, /* inputProc */
incrblobOutput, /* outputProc */
incrblobSeek, /* seekProc */
0, /* setOptionProc */
0, /* getOptionProc */
incrblobWatch, /* watchProc (this is a no-op) */
incrblobHandle, /* getHandleProc (always returns error) */
0, /* close2Proc */
0, /* blockModeProc */
0, /* flushProc */
0, /* handlerProc */
0, /* wideSeekProc */
};
 
/*
** Create a new incrblob channel.
*/
static int count = 0;
static int createIncrblobChannel(
Tcl_Interp interp,
SqliteDb pDb,
string zDb,
string zTable,
string zColumn,
sqlite_int64 iRow,
int isReadonly
){
IncrblobChannel p;
sqlite3 db = pDb.db;
sqlite3_blob pBlob;
int rc;
int flags = TCL.Tcl_READABLE|(isReadonly ? 0 : TCL.Tcl_WRITABLE);
 
/* This variable is used to name the channels: "incrblob_[incr count]" */
//static int count = 0;
string zChannel = "";//string[64];
 
rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRow, !isReadonly, pBlob);
if( rc!=SQLITE_OK ){
TCL.Tcl_SetResult(interp, sqlite3_errmsg(pDb.db), TCL.Tcl_VOLATILE);
return TCL.TCL_ERROR;
}
 
p = new IncrblobChannel();//(IncrblobChannel )Tcl_Alloc(sizeof(IncrblobChannel));
p.iSeek = 0;
p.pBlob = pBlob;
 
sqlite3_snprintf(64, zChannel, "incrblob_%d", ++count);
p.channel = TCL.Tcl_CreateChannel(IncrblobChannelType, zChannel, p, flags);
TCL.Tcl_RegisterChannel(interp, p.channel);
 
/* Link the new channel into the SqliteDb.pIncrblob list. */
p.pNext = pDb.pIncrblob;
p.pPrev = null;
if( p.pNext!=null ){
p.pNext.pPrev = p;
}
pDb.pIncrblob = p;
p.pDb = pDb;
 
TCL.Tcl_SetResult(interp, Tcl_GetChannelName(p.channel), TCL.Tcl_VOLATILE);
return TCL.TCL_OK;
}
#else // * else clause for "#if !SQLITE_OMIT_INCRBLOB" */
//#define closeIncrblobChannels(pDb)
static void closeIncrblobChannels( SqliteDb pDb )
{
}
#endif
 
/*
** Look at the script prefix in pCmd. We will be executing this script
** after first appending one or more arguments. This routine analyzes
** the script to see if it is safe to use TCL.Tcl_EvalObjv() on the script
** rather than the more general TCL.Tcl_EvalEx(). TCL.Tcl_EvalObjv() is much
** faster.
**
** Scripts that are safe to use with TCL.Tcl_EvalObjv() consists of a
** command name followed by zero or more arguments with no [...] or $
** or {...} or ; to be seen anywhere. Most callback scripts consist
** of just a single procedure name and they meet this requirement.
*/
static int safeToUseEvalObjv( Tcl_Interp interp, Tcl_Obj pCmd )
{
/* We could try to do something with TCL.Tcl_Parse(). But we will instead
** just do a search for forbidden characters. If any of the forbidden
** characters appear in pCmd, we will report the string as unsafe.
*/
string z;
int n = 0;
z = TCL.Tcl_GetStringFromObj( pCmd, out n );
while ( n-- > 0 )
{
int c = z[n];// *( z++ );
if ( c == '$' || c == '[' || c == ';' )
return 0;
}
return 1;
}
 
/*
** Find an SqlFunc structure with the given name. Or create a new
** one if an existing one cannot be found. Return a pointer to the
** structure.
*/
static SqlFunc findSqlFunc( SqliteDb pDb, string zName )
{
SqlFunc p, pNew;
int i;
pNew = new SqlFunc();//(SqlFunc)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 );
//pNew.zName = (char)&pNew[1];
//for(i=0; zName[i]; i++){ pNew.zName[i] = tolower(zName[i]); }
//pNew.zName[i] = 0;
pNew.zName = zName.ToLower();
for ( p = pDb.pFunc; p != null; p = p.pNext )
{
if ( p.zName == pNew.zName )
{
//Tcl_Free((char)pNew);
return p;
}
}
pNew.interp = pDb.interp;
pNew.pScript = null;
pNew.pNext = pDb.pFunc;
pDb.pFunc = pNew;
return pNew;
}
 
/*
** Finalize and free a list of prepared statements
*/
static void flushStmtCache( SqliteDb pDb )
{
SqlPreparedStmt pPreStmt;
 
while ( pDb.stmtList != null )
{
sqlite3_finalize( pDb.stmtList.pStmt );
pPreStmt = pDb.stmtList;
pDb.stmtList = pDb.stmtList.pNext;
TCL.Tcl_Free( ref pPreStmt );
}
pDb.nStmt = 0;
pDb.stmtLast = null;
}
 
/*
** TCL calls this procedure when an sqlite3 database command is
** deleted.
*/
static void DbDeleteCmd( ref object db )
{
SqliteDb pDb = (SqliteDb)db;
flushStmtCache( pDb );
closeIncrblobChannels( pDb );
sqlite3_close( pDb.db );
while ( pDb.pFunc != null )
{
SqlFunc pFunc = pDb.pFunc;
pDb.pFunc = pFunc.pNext;
TCL.Tcl_DecrRefCount( ref pFunc.pScript );
TCL.Tcl_Free( ref pFunc );
}
while ( pDb.pCollate != null )
{
SqlCollate pCollate = pDb.pCollate;
pDb.pCollate = pCollate.pNext;
TCL.Tcl_Free( ref pCollate );
}
if ( pDb.zBusy != null )
{
TCL.Tcl_Free( ref pDb.zBusy );
}
if ( pDb.zTrace != null )
{
TCL.Tcl_Free( ref pDb.zTrace );
}
if ( pDb.zProfile != null )
{
TCL.Tcl_Free( ref pDb.zProfile );
}
if ( pDb.zAuth != null )
{
TCL.Tcl_Free( ref pDb.zAuth );
}
if ( pDb.zNull != null )
{
TCL.Tcl_Free( ref pDb.zNull );
}
if ( pDb.pUpdateHook != null )
{
TCL.Tcl_DecrRefCount( ref pDb.pUpdateHook );
}
if ( pDb.pRollbackHook != null )
{
TCL.Tcl_DecrRefCount( ref pDb.pRollbackHook );
}
if ( pDb.pWalHook != null )
{
TCL.Tcl_DecrRefCount( ref pDb.pWalHook );
}
if ( pDb.pCollateNeeded != null )
{
TCL.Tcl_DecrRefCount( ref pDb.pCollateNeeded );
}
TCL.Tcl_Free( ref pDb );
}
 
/*
** This routine is called when a database file is locked while trying
** to execute SQL.
*/
static int DbBusyHandler( object cd, int nTries )
{
SqliteDb pDb = (SqliteDb)cd;
int rc;
StringBuilder zVal = new StringBuilder( 30 );//char zVal[30];
 
sqlite3_snprintf( 30, zVal, "%d", nTries );
rc = TCL.Tcl_VarEval( pDb.interp, pDb.zBusy, " ", zVal.ToString(), null );
if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
{
return 0;
}
return 1;
}
 
#if !SQLITE_OMIT_PROGRESS_CALLBACK
/*
** This routine is invoked as the 'progress callback' for the database.
*/
static int DbProgressHandler( object cd )
{
SqliteDb pDb = (SqliteDb)cd;
int rc;
 
Debug.Assert( pDb.zProgress != null );
rc = TCL.Tcl_Eval( pDb.interp, pDb.zProgress );
if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
{
return 1;
}
return 0;
}
#endif
 
#if !SQLITE_OMIT_TRACE
/*
** This routine is called by the SQLite trace handler whenever a new
** block of SQL is executed. The TCL script in pDb.zTrace is executed.
*/
static void DbTraceHandler( object cd, string zSql )
{
SqliteDb pDb = (SqliteDb)cd;
TclObject str = null;
 
TCL.Tcl_DStringInit( out str );
TCL.Tcl_DStringAppendElement( str, pDb.zTrace );
TCL.Tcl_DStringAppendElement( str, " {" + zSql + "}" );
TCL.Tcl_EvalObjEx( pDb.interp, str, 0 );// TCL.Tcl_Eval( pDb.interp, TCL.Tcl_DStringValue( ref str ) );
TCL.Tcl_DStringFree( ref str );
TCL.Tcl_ResetResult( pDb.interp );
}
#endif
 
#if !SQLITE_OMIT_TRACE
/*
** This routine is called by the SQLite profile handler after a statement
** SQL has executed. The TCL script in pDb.zProfile is evaluated.
*/
static void DbProfileHandler( object cd, string zSql, sqlite_int64 tm )
{
SqliteDb pDb = (SqliteDb)cd;
TclObject str = null;
StringBuilder zTm = new StringBuilder( 100 );//char zTm[100];
 
sqlite3_snprintf( 100, zTm, "%lld", tm );
TCL.Tcl_DStringInit( out str );
TCL.Tcl_DStringAppendElement( str, pDb.zProfile );
TCL.Tcl_DStringAppendElement( str, " {" + zSql + "}" );
TCL.Tcl_DStringAppendElement( str, " {" + zTm.ToString() + "}" );
TCL.Tcl_Eval( pDb.interp, str.ToString() );
TCL.Tcl_DStringFree( ref str );
TCL.Tcl_ResetResult( pDb.interp );
}
#endif
 
/*
** This routine is called when a transaction is committed. The
** TCL script in pDb.zCommit is executed. If it returns non-zero or
** if it throws an exception, the transaction is rolled back instead
** of being committed.
*/
static int DbCommitHandler( object cd )
{
SqliteDb pDb = (SqliteDb)cd;
int rc;
 
rc = TCL.Tcl_Eval( pDb.interp, pDb.zCommit );
if ( rc != TCL.TCL_OK || atoi( TCL.Tcl_GetStringResult( pDb.interp ) ) != 0 )
{
return 1;
}
return 0;
}
 
static void DbRollbackHandler( object _object )
{
SqliteDb pDb = (SqliteDb)_object;
Debug.Assert( pDb.pRollbackHook != null );
if ( TCL.TCL_OK != TCL.Tcl_EvalObjEx( pDb.interp, pDb.pRollbackHook, 0 ) )
{
TCL.Tcl_BackgroundError( pDb.interp );
}
}
 
/*
** This procedure handles wal_hook callbacks.
*/
static int DbWalHandler(
object clientData,
sqlite3 db,
string zDb,
int nEntry
)
{
int ret = SQLITE_OK;
Tcl_Obj p;
SqliteDb pDb = (SqliteDb)clientData;
Tcl_Interp interp = pDb.interp;
Debug.Assert( pDb.pWalHook != null );
 
p = TCL.Tcl_DuplicateObj( pDb.pWalHook );
TCL.Tcl_IncrRefCount( p );
TCL.Tcl_ListObjAppendElement( interp, p, TCL.Tcl_NewStringObj( zDb, -1 ) );
TCL.Tcl_ListObjAppendElement( interp, p, TCL.Tcl_NewIntObj( nEntry ) );
if ( TCL.TCL_OK != TCL.Tcl_EvalObjEx( interp, p, 0 )
|| TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, TCL.Tcl_GetObjResult( interp ), out ret )
)
{
TCL.Tcl_BackgroundError( interp );
}
TCL.Tcl_DecrRefCount( ref p );
 
return ret;
}
 
#if (SQLITE_TEST) && (SQLITE_ENABLE_UNLOCK_NOTIFY)
static void setTestUnlockNotifyVars(Tcl_Interp interp, int iArg, int nArg){
char zBuf[64];
sprintf(zBuf, "%d", iArg);
Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY);
sprintf(zBuf, "%d", nArg);
Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY);
}
#else
//# define setTestUnlockNotifyVars(x,y,z)
#endif
 
#if SQLITE_ENABLE_UNLOCK_NOTIFY
static void DbUnlockNotify(void **apArg, int nArg){
int i;
for(i=0; i<nArg; i++){
const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
SqliteDb *pDb = (SqliteDb )apArg[i];
setTestUnlockNotifyVars(pDb.interp, i, nArg);
Debug.Assert( pDb.pUnlockNotify);
Tcl_EvalObjEx(pDb.interp, pDb.pUnlockNotify, flags);
Tcl_DecrRefCount(pDb.pUnlockNotify);
pDb.pUnlockNotify = 0;
}
}
#endif
 
static void DbUpdateHandler(
object p,
int op,
string zDb,
string zTbl,
sqlite_int64 rowid
)
{
SqliteDb pDb = (SqliteDb)p;
Tcl_Obj pCmd;
 
Debug.Assert( pDb.pUpdateHook != null );
Debug.Assert( op == SQLITE_INSERT || op == SQLITE_UPDATE || op == SQLITE_DELETE );
 
pCmd = TCL.Tcl_DuplicateObj( pDb.pUpdateHook );
TCL.Tcl_IncrRefCount( pCmd );
TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj(
( ( op == SQLITE_INSERT ) ? "INSERT" : ( op == SQLITE_UPDATE ) ? "UPDATE" : "DELETE" ), -1 ) );
TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj( zDb, -1 ) );
TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewStringObj( zTbl, -1 ) );
TCL.Tcl_ListObjAppendElement( null, pCmd, TCL.Tcl_NewWideIntObj( rowid ) );
TCL.Tcl_EvalObjEx( pDb.interp, pCmd, TCL.TCL_EVAL_DIRECT );
TCL.Tcl_DecrRefCount( ref pCmd );
}
 
static void tclCollateNeeded(
object pCtx,
sqlite3 db,
int enc,
string zName
)
{
SqliteDb pDb = (SqliteDb)pCtx;
Tcl_Obj pScript = TCL.Tcl_DuplicateObj( pDb.pCollateNeeded );
TCL.Tcl_IncrRefCount( pScript );
TCL.Tcl_ListObjAppendElement( null, pScript, TCL.Tcl_NewStringObj( zName, -1 ) );
TCL.Tcl_EvalObjEx( pDb.interp, pScript, 0 );
TCL.Tcl_DecrRefCount( ref pScript );
}
 
/*
** This routine is called to evaluate an SQL collation function implemented
** using TCL script.
*/
static int tclSqlCollate(
object pCtx,
int nA,
string zA,
int nB,
string zB
)
{
SqlCollate p = (SqlCollate)pCtx;
Tcl_Obj pCmd;
 
pCmd = TCL.Tcl_NewStringObj( p.zScript, -1 );
TCL.Tcl_IncrRefCount( pCmd );
TCL.Tcl_ListObjAppendElement( p.interp, pCmd, TCL.Tcl_NewStringObj( zA, nA ) );
TCL.Tcl_ListObjAppendElement( p.interp, pCmd, TCL.Tcl_NewStringObj( zB, nB ) );
TCL.Tcl_EvalObjEx( p.interp, pCmd, TCL.TCL_EVAL_DIRECT );
TCL.Tcl_DecrRefCount( ref pCmd );
return ( atoi( TCL.Tcl_GetStringResult( p.interp ) ) );
}
 
/*
** This routine is called to evaluate an SQL function implemented
** using TCL script.
*/
static void tclSqlFunc( sqlite3_context context, int argc, sqlite3_value[] argv )
{
SqlFunc p = (SqlFunc)sqlite3_user_data( context );
Tcl_Obj pCmd = null;
int i;
int rc;
 
if ( argc == 0 )
{
/* If there are no arguments to the function, call TCL.Tcl_EvalObjEx on the
** script object directly. This allows the TCL compiler to generate
** bytecode for the command on the first invocation and thus make
** subsequent invocations much faster. */
pCmd = p.pScript;
TCL.Tcl_IncrRefCount( pCmd );
rc = TCL.Tcl_EvalObjEx( p.interp, pCmd, 0 );
TCL.Tcl_DecrRefCount( ref pCmd );
}
else
{
/* If there are arguments to the function, make a shallow copy of the
** script object, lappend the arguments, then evaluate the copy.
**
** By "shallow" copy, we mean a only the outer list Tcl_Obj is duplicated.
** The new Tcl_Obj contains pointers to the original list elements.
** That way, when TCL.Tcl_EvalObjv() is run and shimmers the first element
** of the list to tclCmdNameType, that alternate representation will
** be preserved and reused on the next invocation.
*/
Tcl_Obj[] aArg = null;
int nArg = 0;
if ( TCL.Tcl_ListObjGetElements( p.interp, p.pScript, out nArg, out aArg ) )
{
sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
return;
}
pCmd = TCL.Tcl_NewListObj( nArg, aArg );
TCL.Tcl_IncrRefCount( pCmd );
for ( i = 0; i < argc; i++ )
{
sqlite3_value pIn = argv[i];
Tcl_Obj pVal;
 
/* Set pVal to contain the i'th column of this row. */
switch ( sqlite3_value_type( pIn ) )
{
case SQLITE_BLOB:
{
int bytes = sqlite3_value_bytes( pIn );
pVal = TCL.Tcl_NewByteArrayObj( sqlite3_value_blob( pIn ), bytes );
break;
}
case SQLITE_INTEGER:
{
sqlite_int64 v = sqlite3_value_int64( pIn );
if ( v >= -2147483647 && v <= 2147483647 )
{
pVal = TCL.Tcl_NewIntObj( (int)v );
}
else
{
pVal = TCL.Tcl_NewWideIntObj( v );
}
break;
}
case SQLITE_FLOAT:
{
double r = sqlite3_value_double( pIn );
pVal = TCL.Tcl_NewDoubleObj( r );
break;
}
case SQLITE_NULL:
{
pVal = TCL.Tcl_NewStringObj( "", 0 );
break;
}
default:
{
int bytes = sqlite3_value_bytes( pIn );
pVal = TCL.Tcl_NewStringObj( sqlite3_value_text( pIn ), bytes );
break;
}
}
rc = TCL.Tcl_ListObjAppendElement( p.interp, pCmd, pVal ) ? 1 : 0;
if ( rc != 0 )
{
TCL.Tcl_DecrRefCount( ref pCmd );
sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
return;
}
}
if ( p.useEvalObjv == 0 )
{
/* TCL.Tcl_EvalObjEx() will automatically call TCL.Tcl_EvalObjv() if pCmd
** is a list without a string representation. To prevent this from
** happening, make sure pCmd has a valid string representation */
TCL.Tcl_GetString( pCmd );
}
rc = TCL.Tcl_EvalObjEx( p.interp, pCmd, TCL.TCL_EVAL_DIRECT );
TCL.Tcl_DecrRefCount( ref pCmd );
}
 
if ( rc != 0 && rc != TCL.TCL_RETURN )
{
sqlite3_result_error( context, TCL.Tcl_GetStringResult( p.interp ), -1 );
}
else
{
Tcl_Obj pVar = TCL.Tcl_GetObjResult( p.interp );
int n = 0;
string data = "";
Tcl_WideInt v = 0;
double r = 0;
string zType = pVar.typePtr;//string zType = (pVar.typePtr ? pVar.typePtr.name : "");
if ( zType == "bytearray" )
{ //&& pVar.bytes==0 ){
/* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
data = Encoding.UTF8.GetString( TCL.Tcl_GetByteArrayFromObj( pVar, out n ) );
sqlite3_result_blob( context, data, n, null );
}
else if ( zType == "boolean" )
{
TCL.Tcl_GetIntFromObj( null, pVar, out n );
sqlite3_result_int( context, n );
}
else if ( zType == "wideint" ||
zType == "int" || Int64.TryParse( pVar.ToString(), out v ) )
{
TCL.Tcl_GetWideIntFromObj( null, pVar, out v );
sqlite3_result_int64( context, v );
}
else if ( zType == "double" || Double.TryParse( pVar.ToString(), out r ) )
{
TCL.Tcl_GetDoubleFromObj( null, pVar, out r );
sqlite3_result_double( context, r );
}
else
{
data = TCL.Tcl_GetStringFromObj( pVar, n );
n = data.Length;
sqlite3_result_text( context, data, n, SQLITE_TRANSIENT );
}
}
}
 
#if !SQLITE_OMIT_AUTHORIZATION
/*
** This is the authentication function. It appends the authentication
** type code and the two arguments to zCmd[] then invokes the result
** on the interpreter. The reply is examined to determine if the
** authentication fails or succeeds.
*/
static int auth_callback(
object pArg,
int code,
const string zArg1,
const string zArg2,
const string zArg3,
const string zArg4
){
string zCode;
TCL.Tcl_DString str;
int rc;
const string zReply;
SqliteDb pDb = (SqliteDb)pArg;
if( pdb.disableAuth ) return SQLITE_OK;
 
switch( code ){
case SQLITE_COPY : zCode="SQLITE_COPY"; break;
case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break;
case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break;
case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break;
case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break;
case SQLITE_DELETE : zCode="SQLITE_DELETE"; break;
case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break;
case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break;
case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break;
case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break;
case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break;
case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break;
case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break;
case SQLITE_INSERT : zCode="SQLITE_INSERT"; break;
case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break;
case SQLITE_READ : zCode="SQLITE_READ"; break;
case SQLITE_SELECT : zCode="SQLITE_SELECT"; break;
case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break;
case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break;
case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break;
case SQLITE_DETACH : zCode="SQLITE_DETACH"; break;
case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break;
case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break;
case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break;
case SQLITE_SAVEPOINT : zCode="SQLITE_SAVEPOINT"; break;
default : zCode="????"; break;
}
TCL.Tcl_DStringInit(&str);
TCL.Tcl_DStringAppend(&str, pDb.zAuth, -1);
TCL.Tcl_DStringAppendElement(&str, zCode);
TCL.Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
TCL.Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
TCL.Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
TCL.Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
rc = TCL.Tcl_GlobalEval(pDb.interp, TCL.Tcl_DStringValue(&str));
TCL.Tcl_DStringFree(&str);
zReply = TCL.Tcl_GetStringResult(pDb.interp);
if( strcmp(zReply,"SQLITE_OK")==0 ){
rc = SQLITE_OK;
}else if( strcmp(zReply,"SQLITE_DENY")==0 ){
rc = SQLITE_DENY;
}else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
rc = SQLITE_IGNORE;
}else{
rc = 999;
}
return rc;
}
#endif // * SQLITE_OMIT_AUTHORIZATION */
 
/*
** zText is a pointer to text obtained via an sqlite3_result_text()
** or similar interface. This routine returns a Tcl string object,
** reference count set to 0, containing the text. If a translation
** between iso8859 and UTF-8 is required, it is preformed.
*/
static Tcl_Obj dbTextToObj( string zText )
{
Tcl_Obj pVal;
#if UTF_TRANSLATION_NEEDED
//TCL.Tcl_DString dCol;
//TCL.Tcl_DStringInit(&dCol);
//TCL.Tcl_ExternalToUtfDString(NULL, zText, -1, dCol);
//pVal = TCL.Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
//TCL.Tcl_DStringFree(ref dCol);
if (zText.Length == Encoding.UTF8.GetByteCount(zText)) pVal = TCL.Tcl_NewStringObj( zText, -1 );
else pVal = TCL.Tcl_NewStringObj( zText, -1 );
#else
pVal = TCL.Tcl_NewStringObj( zText, -1 );
#endif
return pVal;
}
 
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
** fails.
**
** The interface is like "readline" but no command-line editing
** is done.
**
** copied from shell.c from '.import' command
*/
//static char *local_getline(string zPrompt, FILE *in){
// string zLine;
// int nLine;
// int n;
// int eol;
 
// nLine = 100;
// zLine = malloc( nLine );
// if( zLine==0 ) return 0;
// n = 0;
// eol = 0;
// while( !eol ){
// if( n+100>nLine ){
// nLine = nLine*2 + 100;
// zLine = realloc(zLine, nLine);
// if( zLine==0 ) return 0;
// }
// if( fgets(&zLine[n], nLine - n, in)==0 ){
// if( n==0 ){
// free(zLine);
// return 0;
// }
// zLine[n] = 0;
// eol = 1;
// break;
// }
// while( zLine[n] ){ n++; }
// if( n>0 && zLine[n-1]=='\n' ){
// n--;
// zLine[n] = 0;
// eol = 1;
// }
// }
// zLine = realloc( zLine, n+1 );
// return zLine;
//}
 
 
/*
** This function is part of the implementation of the command:
**
** $db transaction [-deferred|-immediate|-exclusive] SCRIPT
**
** It is invoked after evaluating the script SCRIPT to commit or rollback
** the transaction or savepoint opened by the [transaction] command.
*/
static int DbTransPostCmd(
object data, /* data[0] is the Sqlite3Db* for $db */
Tcl_Interp interp, /* Tcl interpreter */
int result /* Result of evaluating SCRIPT */
)
{
string[] azEnd = {
"RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */
"COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */
"ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction",
"ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */
};
SqliteDb pDb = (SqliteDb)data;
int rc = result;
string zEnd;
 
pDb.nTransaction--;
zEnd = azEnd[( ( rc == TCL.TCL_ERROR ) ? 1 : 0 ) * 2 + ( ( pDb.nTransaction == 0 ) ? 1 : 0 )];
 
pDb.disableAuth++;
if ( sqlite3_exec( pDb.db, zEnd, 0, 0, 0 ) != 0 )
{
/* This is a tricky scenario to handle. The most likely cause of an
** error is that the exec() above was an attempt to commit the
** top-level transaction that returned SQLITE_BUSY. Or, less likely,
** that an IO-error has occured. In either case, throw a Tcl exception
** and try to rollback the transaction.
**
** But it could also be that the user executed one or more BEGIN,
** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
** this method's logic. Not clear how this would be best handled.
*/
if ( rc != TCL.TCL_ERROR )
{
TCL.Tcl_AppendResult( interp, sqlite3_errmsg( pDb.db ), 0 );
rc = TCL.TCL_ERROR;
}
sqlite3_exec( pDb.db, "ROLLBACK", 0, 0, 0 );
}
pDb.disableAuth--;
 
return rc;
}
 
/*
** Search the cache for a prepared-statement object that implements the
** first SQL statement in the buffer pointed to by parameter zIn. If
** no such prepared-statement can be found, allocate and prepare a new
** one. In either case, bind the current values of the relevant Tcl
** variables to any $var, :var or @var variables in the statement. Before
** returning, set *ppPreStmt to point to the prepared-statement object.
**
** Output parameter *pzOut is set to point to the next SQL statement in
** buffer zIn, or to the '\0' byte at the end of zIn if there is no
** next statement.
**
** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned
** and an error message loaded into interpreter pDb.interp.
*/
static int dbPrepareAndBind(
SqliteDb pDb, /* Database object */
string zIn, /* SQL to compile */
ref string pzOut, /* OUT: Pointer to next SQL statement */
ref SqlPreparedStmt ppPreStmt /* OUT: Object used to cache statement */
)
{
string zSql = zIn; /* Pointer to first SQL statement in zIn */
sqlite3_stmt pStmt = null; /* Prepared statement object */
SqlPreparedStmt pPreStmt; /* Pointer to cached statement */
int nSql; /* Length of zSql in bytes */
int nVar = 0; /* Number of variables in statement */
int iParm = 0; /* Next free entry in apParm */
int i;
Tcl_Interp interp = pDb.interp;
 
pzOut = null;
ppPreStmt = null;
 
/* Trim spaces from the start of zSql and calculate the remaining length. */
zSql = zSql.TrimStart(); //while ( isspace( zSql[0] ) ) { zSql++; }
nSql = strlen30( zSql );
 
for ( pPreStmt = pDb.stmtList; pPreStmt != null; pPreStmt = pPreStmt.pNext )
{
int n = pPreStmt.nSql;
if ( nSql >= n
&& zSql.StartsWith(pPreStmt.zSql)
&& ( nSql == n /* zSql[n]==0 */|| zSql[n - 1] == ';' )
)
{
pStmt = pPreStmt.pStmt;
/* Restore aMem values */
if ( pStmt.aMem.Length < pPreStmt.aMem.Length )
Array.Resize( ref pStmt.aMem, pPreStmt.aMem.Length );
for ( int ix = 0; ix < pPreStmt.aMem.Length; ix++ )
{
pPreStmt.aMem[ix].CopyTo( ref pStmt.aMem[ix] );
}
 
pzOut = zSql.Substring( pPreStmt.nSql );
 
/* When a prepared statement is found, unlink it from the
** cache list. It will later be added back to the beginning
** of the cache list in order to implement LRU replacement.
*/
if ( pPreStmt.pPrev != null )
{
pPreStmt.pPrev.pNext = pPreStmt.pNext;
}
else
{
pDb.stmtList = pPreStmt.pNext;
}
if ( pPreStmt.pNext != null )
{
pPreStmt.pNext.pPrev = pPreStmt.pPrev;
}
else
{
pDb.stmtLast = pPreStmt.pPrev;
}
pDb.nStmt--;
nVar = sqlite3_bind_parameter_count( pStmt );
break;
}
}
 
/* If no prepared statement was found. Compile the SQL text. Also allocate
** a new SqlPreparedStmt structure. */
if ( pPreStmt == null )
{
int nByte;
 
if ( SQLITE_OK != sqlite3_prepare_v2( pDb.db, zSql, -1, ref pStmt, ref pzOut ) )
{
TCL.Tcl_SetObjResult( interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
pPreStmt = new SqlPreparedStmt();// (SqlPreparedStmt)Tcl_Alloc( nByte );
return TCL.TCL_ERROR;
}
if ( pStmt == null )
{
if ( SQLITE_OK != sqlite3_errcode( pDb.db ) )
{
/* A compile-time error in the statement. */
TCL.Tcl_SetObjResult( interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
return TCL.TCL_ERROR;
}
else
{
/* The statement was a no-op. Continue to the next statement
** in the SQL string.
*/
return TCL.TCL_OK;
}
}
 
Debug.Assert( pPreStmt == null );
nVar = sqlite3_bind_parameter_count( pStmt );
//nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj );
pPreStmt = new SqlPreparedStmt();// (SqlPreparedStmt)Tcl_Alloc( nByte );
//memset(pPreStmt, 0, nByte);
 
pPreStmt.pStmt = pStmt;
pPreStmt.nSql = ( zSql.Length - pzOut.Length );
pPreStmt.zSql = sqlite3_sql( pStmt );
pPreStmt.apParm = new TclObject[nVar];//pPreStmt[1];
}
Debug.Assert( pPreStmt != null );
Debug.Assert( strlen30( pPreStmt.zSql ) == pPreStmt.nSql );
Debug.Assert( zSql.StartsWith( pPreStmt.zSql ) );
 
/* Bind values to parameters that begin with $ or : */
for ( i = 1; i <= nVar; i++ )
{
string zVar = sqlite3_bind_parameter_name( pStmt, i );
if ( !String.IsNullOrEmpty( zVar ) && ( zVar[0] == '$' || zVar[0] == ':' || zVar[0] == '@' ) )
{
Tcl_Obj pVar = TCL.Tcl_GetVar2Ex( interp, zVar.Substring( 1 ), null, 0 );
if ( pVar != null && pVar.typePtr != "null" )
{
int n = 0;
string data;
string zType = pVar.typePtr;
//char c = zType[0];
if ( zVar[0] == '@' ||
( zType == "bytearray" ) )// TODO -- && pVar.bytes == 0 ) )
{
/* Load a BLOB type if the Tcl variable is a bytearray and
** it has no string representation or the host
** parameter name begins with "@". */
if ( zVar[0] == '@' || pVar.stringRep == null )
sqlite3_bind_blob( pStmt, i, TCL.Tcl_GetByteArrayFromObj( pVar, out n ), n, SQLITE_STATIC );
else
sqlite3_bind_text( pStmt, i, TCL.Tcl_GetStringFromObj( pVar, out n ), n, SQLITE_STATIC );
TCL.Tcl_IncrRefCount( pVar );
pPreStmt.apParm[iParm++] = pVar;
}
else if ( zType == "boolean" )
{
TCL.Tcl_GetIntFromObj( interp, pVar, out n );
sqlite3_bind_int( pStmt, i, n );
}
else if ( zType == "double" )
{
double r = 0;
TCL.Tcl_GetDoubleFromObj( interp, pVar, out r );
sqlite3_bind_double( pStmt, i, r );
}
else if ( zType == "wideint" ||
zType == "int" )
{
Tcl_WideInt v = 0;
TCL.Tcl_GetWideIntFromObj( interp, pVar, out v );
sqlite3_bind_int64( pStmt, i, v );
}
else
{
data = TCL.Tcl_GetStringFromObj( pVar, out n );
sqlite3_bind_text( pStmt, i, data, n, SQLITE_STATIC );
TCL.Tcl_IncrRefCount( pVar );
pPreStmt.apParm[iParm++] = pVar;
}
}
else
{
sqlite3_bind_null( pStmt, i );
}
}
}
pPreStmt.nParm = iParm;
/* save aMem values for later reuse */
pPreStmt.aMem = new Mem[pPreStmt.pStmt.aMem.Length];
for ( int ix = 0; ix < pPreStmt.pStmt.aMem.Length; ix++ )
{
pPreStmt.pStmt.aMem[ix].CopyTo( ref pPreStmt.aMem[ix] );
}
ppPreStmt = pPreStmt;
 
return TCL.TCL_OK;
}
 
 
/*
** Release a statement reference obtained by calling dbPrepareAndBind().
** There should be exactly one call to this function for each call to
** dbPrepareAndBind().
**
** If the discard parameter is non-zero, then the statement is deleted
** immediately. Otherwise it is added to the LRU list and may be returned
** by a subsequent call to dbPrepareAndBind().
*/
static void dbReleaseStmt(
SqliteDb pDb, /* Database handle */
SqlPreparedStmt pPreStmt, /* Prepared statement handle to release */
int discard /* True to delete (not cache) the pPreStmt */
)
{
int i;
 
/* Free the bound string and blob parameters */
for ( i = 0; i < pPreStmt.nParm; i++ )
{
TCL.Tcl_DecrRefCount( ref pPreStmt.apParm[i] );
}
pPreStmt.nParm = 0;
 
if ( pDb.maxStmt <= 0 || discard != 0 )
{
/* If the cache is turned off, deallocated the statement */
sqlite3_finalize( pPreStmt.pStmt );
TCL.Tcl_Free( ref pPreStmt );
}
else
{
/* Add the prepared statement to the beginning of the cache list. */
pPreStmt.pNext = pDb.stmtList;
pPreStmt.pPrev = null;
if ( pDb.stmtList != null )
{
pDb.stmtList.pPrev = pPreStmt;
}
pDb.stmtList = pPreStmt;
if ( pDb.stmtLast == null )
{
Debug.Assert( pDb.nStmt == 0 );
pDb.stmtLast = pPreStmt;
}
else
{
Debug.Assert( pDb.nStmt > 0 );
}
pDb.nStmt++;
 
/* If we have too many statement in cache, remove the surplus from
** the end of the cache list. */
while ( pDb.nStmt > pDb.maxStmt )
{
sqlite3_finalize( pDb.stmtLast.pStmt );
pDb.stmtLast = pDb.stmtLast.pPrev;
TCL.Tcl_Free( ref pDb.stmtLast.pNext );
pDb.stmtLast.pNext = null;
pDb.nStmt--;
}
}
}
 
/*
** Structure used with dbEvalXXX() functions:
**
** dbEvalInit()
** dbEvalStep()
** dbEvalFinalize()
** dbEvalRowInfo()
** dbEvalColumnValue()
*/
//typedef struct DbEvalContext DbEvalContext;
public class DbEvalContext
{
public SqliteDb pDb; /* Database handle */
public Tcl_Obj pSql; /* Object holding string zSql */
public string zSql; /* Remaining SQL to execute */
public SqlPreparedStmt pPreStmt; /* Current statement */
public int nCol; /* Number of columns returned by pStmt */
public Tcl_Obj pArray; /* Name of array variable */
public Tcl_Obj[] apColName; /* Array of column names */
 
public void Clear()
{
pDb = null;
pSql = null;
zSql = null;
pPreStmt = null;
pArray = null;
apColName = null;
 
}
};
 
/*
** Release any cache of column names currently held as part of
** the DbEvalContext structure passed as the first argument.
*/
static void dbReleaseColumnNames( DbEvalContext p )
{
if ( p.apColName != null )
{
int i;
for ( i = 0; i < p.nCol; i++ )
{
TCL.Tcl_DecrRefCount( ref p.apColName[i] );
}
TCL.Tcl_Free( ref p.apColName );
p.apColName = null;
}
p.nCol = 0;
}
 
/*
** Initialize a DbEvalContext structure.
**
** If pArray is not NULL, then it contains the name of a Tcl array
** variable. The "*" member of this array is set to a list containing
** the names of the columns returned by the statement as part of each
** call to dbEvalStep(), in order from left to right. e.g. if the names
** of the returned columns are a, b and c, it does the equivalent of the
** tcl command:
**
** set ${pArray}() {a b c}
*/
static void dbEvalInit(
DbEvalContext p, /* Pointer to structure to initialize */
SqliteDb pDb, /* Database handle */
Tcl_Obj pSql, /* Object containing SQL script */
Tcl_Obj pArray /* Name of Tcl array to set () element of */
)
{
if ( p != null )
p.Clear();// memset( p, 0, sizeof( DbEvalContext ) );
p.pDb = pDb;
p.zSql = TCL.Tcl_GetString( pSql );
p.pSql = pSql;
TCL.Tcl_IncrRefCount( pSql );
if ( pArray != null )
{
p.pArray = pArray;
TCL.Tcl_IncrRefCount( pArray );
}
}
 
/*
** Obtain information about the row that the DbEvalContext passed as the
** first argument currently points to.
*/
static void dbEvalRowInfo(
DbEvalContext p, /* Evaluation context */
out int pnCol, /* OUT: Number of column names */
out Tcl_Obj[] papColName /* OUT: Array of column names */
)
{
/* Compute column names */
if ( null == p.apColName )
{
sqlite3_stmt pStmt = p.pPreStmt.pStmt;
int i; /* Iterator variable */
int nCol; /* Number of columns returned by pStmt */
Tcl_Obj[] apColName = null; /* Array of column names */
 
p.nCol = nCol = sqlite3_column_count( pStmt );
if ( nCol > 0 )// && ( papColName != null || p.pArray != null ) )
{
apColName = new TclObject[nCol];// (Tcl_Obj*)Tcl_Alloc( sizeof( Tcl_Obj* ) * nCol );
for ( i = 0; i < nCol; i++ )
{
apColName[i] = dbTextToObj( sqlite3_column_name( pStmt, i ) );
TCL.Tcl_IncrRefCount( apColName[i] );
}
p.apColName = apColName;
}
 
/* If results are being stored in an array variable, then create
** the array() entry for that array
*/
if ( p.pArray != null )
{
Tcl_Interp interp = p.pDb.interp;
Tcl_Obj pColList = TCL.Tcl_NewObj();
Tcl_Obj pStar = TCL.Tcl_NewStringObj( "*", -1 );
 
for ( i = 0; i < nCol; i++ )
{
TCL.Tcl_ListObjAppendElement( interp, pColList, apColName[i] );
}
TCL.Tcl_IncrRefCount( pStar );
TCL.Tcl_ObjSetVar2( interp, p.pArray, pStar, pColList, 0 );
TCL.Tcl_DecrRefCount( ref pStar );
}
}
 
//if ( papColName != null )
{
papColName = p.apColName;
}
//if ( pnCol !=0)
{
pnCol = p.nCol;
}
}
 
/*
** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is
** returned, then an error message is stored in the interpreter before
** returning.
**
** A return value of TCL_OK means there is a row of data available. The
** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This
** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK
** is returned, then the SQL script has finished executing and there are
** no further rows available. This is similar to SQLITE_DONE.
*/
static int dbEvalStep( DbEvalContext p )
{
while ( !String.IsNullOrEmpty( p.zSql ) || p.pPreStmt != null )
{
int rc;
if ( p.pPreStmt == null )
{
rc = dbPrepareAndBind( p.pDb, p.zSql, ref p.zSql, ref p.pPreStmt );
if ( rc != TCL.TCL_OK )
return rc;
}
else
{
int rcs;
SqliteDb pDb = p.pDb;
SqlPreparedStmt pPreStmt = p.pPreStmt;
sqlite3_stmt pStmt = pPreStmt.pStmt;
 
rcs = sqlite3_step( pStmt );
if ( rcs == SQLITE_ROW )
{
return TCL.TCL_OK;
}
if ( p.pArray != null )
{
TclObject[] pDummy;
int iDummy;
dbEvalRowInfo( p, out iDummy, out pDummy );
}
rcs = sqlite3_reset( pStmt );
 
pDb.nStep = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, 1 );
pDb.nSort = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_SORT, 1 );
pDb.nIndex = sqlite3_stmt_status( pStmt, SQLITE_STMTSTATUS_AUTOINDEX, 1 );
dbReleaseColumnNames( p );
p.pPreStmt = null;
 
if ( rcs != SQLITE_OK )
{
/* If a run-time error occurs, report the error and stop reading
** the SQL. */
TCL.Tcl_SetObjResult( pDb.interp, dbTextToObj( sqlite3_errmsg( pDb.db ) ) );
dbReleaseStmt( pDb, pPreStmt, 1 );
return TCL.TCL_ERROR;
}
else
{
dbReleaseStmt( pDb, pPreStmt, 0 );
}
}
}
 
/* Finished */
return TCL.TCL_BREAK;
}
 
/*
** Free all resources currently held by the DbEvalContext structure passed
** as the first argument. There should be exactly one call to this function
** for each call to dbEvalInit().
*/
static void dbEvalFinalize( DbEvalContext p )
{
if ( p.pPreStmt != null )
{
sqlite3_reset( p.pPreStmt.pStmt );
dbReleaseStmt( p.pDb, p.pPreStmt, 1 );
p.pPreStmt = null;
}
if ( p.pArray != null )
{
TCL.Tcl_DecrRefCount( ref p.pArray );
p.pArray = null;
}
TCL.Tcl_DecrRefCount( ref p.pSql );
dbReleaseColumnNames( p );
}
 
/*
** Return a pointer to a Tcl_Obj structure with ref-count 0 that contains
** the value for the iCol'th column of the row currently pointed to by
** the DbEvalContext structure passed as the first argument.
*/
static Tcl_Obj dbEvalColumnValue( DbEvalContext p, int iCol )
{
sqlite3_stmt pStmt = p.pPreStmt.pStmt;
switch ( sqlite3_column_type( pStmt, iCol ) )
{
case SQLITE_BLOB:
{
int bytes = sqlite3_column_bytes( pStmt, iCol );
byte[] zBlob = sqlite3_column_blob( pStmt, iCol );
if ( null == zBlob )
bytes = 0;
return TCL.Tcl_NewByteArrayObj( zBlob, bytes );
}
case SQLITE_INTEGER:
{
sqlite_int64 v = sqlite3_column_int64( pStmt, iCol );
if ( v >= -2147483647 && v <= 2147483647 )
{
return TCL.Tcl_NewIntObj( (int)v );
}
else
{
return TCL.Tcl_NewWideIntObj( v );
}
}
case SQLITE_FLOAT:
{
return TCL.Tcl_NewDoubleObj( sqlite3_column_double( pStmt, iCol ) );
}
case SQLITE_NULL:
{
return dbTextToObj( p.pDb.zNull );
}
}
 
return dbTextToObj( sqlite3_column_text( pStmt, iCol ) );
}
 
/*
** If using Tcl version 8.6 or greater, use the NR functions to avoid
** recursive evalution of scripts by the [db eval] and [db trans]
** commands. Even if the headers used while compiling the extension
** are 8.6 or newer, the code still tests the Tcl version at runtime.
** This allows stubs-enabled builds to be used with older Tcl libraries.
*/
#if TCL_MAJOR_VERSION//>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6)
//# define SQLITE_TCL_NRE 1
static int DbUseNre(void){
int major, minor;
Tcl_GetVersion(&major, &minor, 0, 0);
return( (major==8 && minor>=6) || major>8 );
}
#else
/*
** Compiling using headers earlier than 8.6. In this case NR cannot be
** used, so DbUseNre() to always return zero. Add #defines for the other
** Tcl_NRxxx() functions to prevent them from causing compilation errors,
** even though the only invocations of them are within conditional blocks
** of the form:
**
** if( DbUseNre() ) { ... }
*/
const int SQLITE_TCL_NRE = 0; //# define SQLITE_TCL_NRE 0
static bool DbUseNre()
{
return false;
} //# define DbUseNre() 0
//# define Tcl_NRAddCallback(a,b,c,d,e,f) 0
//# define Tcl_NREvalObj(a,b,c) 0
//# define Tcl_NRCreateCommand(a,b,c,d,e,f) 0
#endif
 
/*
** This function is part of the implementation of the command:
**
** $db eval SQL ?ARRAYNAME? SCRIPT
*/
static int DbEvalNextCmd(
object[] data, /* data[0] is the (DbEvalContext) */
Tcl_Interp interp, /* Tcl interpreter */
int result /* Result so far */
)
{
int rc = result; /* Return code */
 
/* The first element of the data[] array is a pointer to a DbEvalContext
** structure allocated using TCL.Tcl_Alloc(). The second element of data[]
** is a pointer to a TCL.Tcl_Obj containing the script to run for each row
** returned by the queries encapsulated in data[0]. */
DbEvalContext p = (DbEvalContext)data[0];
Tcl_Obj pScript = (Tcl_Obj)data[1];
Tcl_Obj pArray = p.pArray;
 
while ( ( rc == TCL.TCL_OK || rc == TCL.TCL_CONTINUE ) && TCL.TCL_OK == ( rc = dbEvalStep( p ) ) )
{
int i;
int nCol;
Tcl_Obj[] apColName;
dbEvalRowInfo( p, out nCol, out apColName );
for ( i = 0; i < nCol; i++ )
{
Tcl_Obj pVal = dbEvalColumnValue( p, i );
if ( pArray == null )
{
TCL.Tcl_ObjSetVar2( interp, apColName[i], null, pVal, 0 );
}
else
{
TCL.Tcl_ObjSetVar2( interp, pArray, apColName[i], pVal, 0 );
}
}
 
/* The required interpreter variables are now populated with the data
** from the current row. If using NRE, schedule callbacks to evaluate
** script pScript, then to invoke this function again to fetch the next
** row (or clean up if there is no next row or the script throws an
** exception). After scheduling the callbacks, return control to the
** caller.
**
** If not using NRE, evaluate pScript directly and continue with the
** next iteration of this while(...) loop. */
if ( DbUseNre() )
{
Debugger.Break();
//TCL.Tcl_NRAddCallback(interp, DbEvalNextCmd, (void)p, (void)pScript, 0, 0);
//return TCL.Tcl_NREvalObj(interp, pScript, 0);
}
else
{
rc = TCL.Tcl_EvalObjEx( interp, pScript, 0 );
}
}
 
TCL.Tcl_DecrRefCount( ref pScript );
dbEvalFinalize( p );
TCL.Tcl_Free( ref p );
 
if ( rc == TCL.TCL_OK || rc == TCL.TCL_BREAK )
{
TCL.Tcl_ResetResult( interp );
rc = TCL.TCL_OK;
}
return rc;
}
 
/*
** The "sqlite" command below creates a new Tcl command for each
** connection it opens to an SQLite database. This routine is invoked
** whenever one of those connection-specific commands is executed
** in Tcl. For example, if you run Tcl code like this:
**
** sqlite3 db1 "my_database"
** db1 close
**
** The first command opens a connection to the "my_database" database
** and calls that connection "db1". The second command causes this
** subroutine to be invoked.
*/
enum DB_enum
{
DB_AUTHORIZER,
DB_BACKUP,
DB_BUSY,
DB_CACHE,
DB_CHANGES,
DB_CLOSE,
DB_COLLATE,
DB_COLLATION_NEEDED,
DB_COMMIT_HOOK,
DB_COMPLETE,
DB_COPY,
DB_ENABLE_LOAD_EXTENSION,
DB_ERRORCODE,
DB_EVAL,
DB_EXISTS,
DB_FUNCTION,
DB_INCRBLOB,
DB_INTERRUPT,
DB_LAST_INSERT_ROWID,
DB_NULLVALUE,
DB_ONECOLUMN,
DB_PROFILE,
DB_PROGRESS,
DB_REKEY,
DB_RESTORE,
DB_ROLLBACK_HOOK,
DB_STATUS,
DB_TIMEOUT,
DB_TOTAL_CHANGES,
DB_TRACE,
DB_TRANSACTION,
DB_UNLOCK_NOTIFY,
DB_UPDATE_HOOK,
DB_VERSION,
DB_WAL_HOOK
};
 
enum TTYPE_enum
{
TTYPE_DEFERRED,
TTYPE_EXCLUSIVE,
TTYPE_IMMEDIATE
};
 
static int DbObjCmd( object cd, Tcl_Interp interp, int objc, Tcl_Obj[] objv )
{
SqliteDb pDb = (SqliteDb)cd;
int choice = 0;
int rc = TCL.TCL_OK;
string[] DB_strs = {
"authorizer", "backup", "busy",
"cache", "changes", "close",
"collate", "collation_needed", "commit_hook",
"complete", "copy", "enable_load_extension",
"errorcode", "eval", "exists",
"function", "incrblob", "interrupt",
"last_insert_rowid", "nullvalue", "onecolumn",
"profile", "progress", "rekey",
"restore", "rollback_hook", "status",
"timeout", "total_changes", "trace",
"transaction", "unlock_notify", "update_hook",
"version", "wal_hook"
};
 
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
if ( objc < 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SUBCOMMAND ..." );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetIndexFromObj( interp, objv[1], DB_strs, "option", 0, out choice ) )
{
return TCL.TCL_ERROR;
}
 
switch ( choice )
{
 
/* $db authorizer ?CALLBACK?
**
** Invoke the given callback to authorize each SQL operation as it is
** compiled. 5 arguments are appended to the callback before it is
** invoked:
**
** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
** (2) First descriptive name (depends on authorization type)
** (3) Second descriptive name
** (4) Name of the database (ex: "main", "temp")
** (5) Name of trigger that is doing the access
**
** The callback should return on of the following strings: SQLITE_OK,
** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error.
**
** If this method is invoked with no arguments, the current authorization
** callback string is returned.
*/
case (int)DB_enum.DB_AUTHORIZER:
{
#if SQLITE_OMIT_AUTHORIZATION
TCL.Tcl_AppendResult( interp, "authorization not available in this build" );
return TCL.TCL_RETURN;
#else
if( objc>3 ){
TCL.Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
return TCL.TCL_ERROR;
}else if( objc==2 ){
if( pDb.zAuth ){
TCL.Tcl_AppendResult(interp, pDb.zAuth);
}
}else{
string zAuth;
int len;
if( pDb.zAuth ){
TCL.Tcl_Free(pDb.zAuth);
}
zAuth = TCL.Tcl_GetStringFromObj(objv[2], len);
if( zAuth && len>0 ){
pDb.zAuth = TCL.Tcl_Alloc( len + 1 );
memcpy(pDb.zAuth, zAuth, len+1);
}else{
pDb.zAuth = 0;
}
if( pDb.zAuth ){
pDb.interp = interp;
sqlite3_set_authorizer(pDb.db, auth_callback, pDb);
}else{
sqlite3_set_authorizer(pDb.db, 0, 0);
}
}
break;
#endif
}
 
/* $db backup ?DATABASE? FILENAME
**
** Open or create a database file named FILENAME. Transfer the
** content of local database DATABASE (default: "main") into the
** FILENAME database.
*/
case (int)DB_enum.DB_BACKUP:
{
string zDestFile;
string zSrcDb;
sqlite3 pDest = null;
sqlite3_backup pBackup;
 
if ( objc == 3 )
{
zSrcDb = "main";
zDestFile = TCL.Tcl_GetString( objv[2] );
}
else if ( objc == 4 )
{
zSrcDb = TCL.Tcl_GetString( objv[2] );
zDestFile = TCL.Tcl_GetString( objv[3] );
}
else
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "?DATABASE? FILENAME" );
return TCL.TCL_ERROR;
}
rc = sqlite3_open( zDestFile, out pDest );
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, "cannot open target database: ",
sqlite3_errmsg( pDest ) );
sqlite3_close( pDest );
return TCL.TCL_ERROR;
}
pBackup = sqlite3_backup_init( pDest, "main", pDb.db, zSrcDb );
if ( pBackup == null )
{
TCL.Tcl_AppendResult( interp, "backup failed: ",
sqlite3_errmsg( pDest ) );
sqlite3_close( pDest );
return TCL.TCL_ERROR;
}
#if SQLITE_HAS_CODEC
if ( pBackup.pSrc.pBt.pPager.pCodec != null )
{
pBackup.pDest.pBt.pPager.xCodec = pBackup.pSrc.pBt.pPager.xCodec;
pBackup.pDest.pBt.pPager.xCodecFree = pBackup.pSrc.pBt.pPager.xCodecFree;
pBackup.pDest.pBt.pPager.xCodecSizeChng = pBackup.pSrc.pBt.pPager.xCodecSizeChng;
pBackup.pDest.pBt.pPager.pCodec = pBackup.pSrc.pBt.pPager.pCodec.Copy();
}
#endif
while ( ( rc = sqlite3_backup_step( pBackup, 100 ) ) == SQLITE_OK )
{
}
sqlite3_backup_finish( pBackup );
if ( rc == SQLITE_DONE )
{
rc = TCL.TCL_OK;
}
else
{
TCL.Tcl_AppendResult( interp, "backup failed: ",
sqlite3_errmsg( pDest ) );
rc = TCL.TCL_ERROR;
}
sqlite3_close( pDest );
break;
}
 
// /* $db busy ?CALLBACK?
// **
// ** Invoke the given callback if an SQL statement attempts to open
// ** a locked database file.
// */
case (int)DB_enum.DB_BUSY:
{
if ( objc > 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "CALLBACK" );
return TCL.TCL_ERROR;
}
else if ( objc == 2 )
{
if ( pDb.zBusy != null )
{
TCL.Tcl_AppendResult( interp, pDb.zBusy );
}
}
else
{
string zBusy;
int len = 0;
if ( pDb.zBusy != null )
{
TCL.Tcl_Free( ref pDb.zBusy );
}
zBusy = TCL.Tcl_GetStringFromObj( objv[2], out len );
if ( zBusy != null && len > 0 )
{
//pDb.zBusy = TCL.Tcl_Alloc( len + 1 );
pDb.zBusy = zBusy;// memcpy( pDb.zBusy, zBusy, len + 1 );
}
else
{
pDb.zBusy = null;
}
if ( pDb.zBusy != null )
{
pDb.interp = interp;
sqlite3_busy_handler( pDb.db, (dxBusy)DbBusyHandler, pDb );
}
else
{
sqlite3_busy_handler( pDb.db, null, null );
}
}
break;
}
 
// /* $db cache flush
// ** $db cache size n
// **
// ** Flush the prepared statement cache, or set the maximum number of
// ** cached statements.
// */
case (int)DB_enum.DB_CACHE:
{
string subCmd;
int n = 0;
 
if ( objc <= 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "cache option ?arg?" );
return TCL.TCL_ERROR;
}
subCmd = TCL.Tcl_GetStringFromObj( objv[2], 0 );
if ( subCmd == "flush" )
{
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "flush" );
return TCL.TCL_ERROR;
}
else
{
flushStmtCache( pDb );
}
}
else if ( subCmd == "size" )
{
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "size n" );
return TCL.TCL_ERROR;
}
else
{
if ( TCL.TCL_ERROR == ( TCL.Tcl_GetIntFromObj( interp, objv[3], out n ) != TCL.TCL_OK ? TCL.TCL_ERROR : TCL.TCL_OK ) )
{
TCL.Tcl_AppendResult( interp, "cannot convert \"",
TCL.Tcl_GetStringFromObj( objv[3], 0 ), "\" to integer", 0 );
return TCL.TCL_ERROR;
}
else
{
if ( n < 0 )
{
flushStmtCache( pDb );
n = 0;
}
else if ( n > MAX_PREPARED_STMTS )
{
n = MAX_PREPARED_STMTS;
}
pDb.maxStmt = n;
}
}
}
else
{
TCL.Tcl_AppendResult( interp, "bad option \"",
TCL.Tcl_GetStringFromObj( objv[2], 0 ), "\": must be flush or size", null );
return TCL.TCL_ERROR;
}
break;
}
 
/* $db changes
**
** Return the number of rows that were modified, inserted, or deleted by
** the most recent INSERT, UPDATE or DELETE statement, not including
** any changes made by trigger programs.
*/
case (int)DB_enum.DB_CHANGES:
{
Tcl_Obj pResult;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
return TCL.TCL_ERROR;
}
pResult = TCL.Tcl_GetObjResult( interp );
TCL.Tcl_SetResult( interp, sqlite3_changes( pDb.db ).ToString(), 0 );
break;
}
 
/* $db close
**
** Shutdown the database
*/
case (int)DB_enum.DB_CLOSE:
{
TCL.Tcl_DeleteCommand( interp, TCL.Tcl_GetStringFromObj( objv[0], 0 ) );
break;
}
 
/*
** $db collate NAME SCRIPT
**
** Create a new SQL collation function called NAME. Whenever
** that function is called, invoke SCRIPT to evaluate the function.
*/
case (int)DB_enum.DB_COLLATE:
{
SqlCollate pCollate;
string zName;
string zScript;
int nScript = 0;
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "NAME SCRIPT" );
return TCL.TCL_ERROR;
}
zName = TCL.Tcl_GetStringFromObj( objv[2], 0 );
zScript = TCL.Tcl_GetStringFromObj( objv[3], nScript );
pCollate = new SqlCollate();//(SqlCollate)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
//if ( pCollate == null ) return TCL.TCL_ERROR;
pCollate.interp = interp;
pCollate.pNext = pDb.pCollate;
pCollate.zScript = zScript; // pCollate[1];
pDb.pCollate = pCollate;
//memcpy( pCollate.zScript, zScript, nScript + 1 );
if ( sqlite3_create_collation( pDb.db, zName, SQLITE_UTF8,
pCollate, (dxCompare)tclSqlCollate ) != 0 )
{
TCL.Tcl_SetResult( interp, sqlite3_errmsg( pDb.db ), TCL.TCL_VOLATILE );
return TCL.TCL_ERROR;
}
break;
}
 
/*
** $db collation_needed SCRIPT
**
** Create a new SQL collation function called NAME. Whenever
** that function is called, invoke SCRIPT to evaluate the function.
*/
case (int)DB_enum.DB_COLLATION_NEEDED:
{
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "SCRIPT" );
return TCL.TCL_ERROR;
}
if ( pDb.pCollateNeeded != null )
{
TCL.Tcl_DecrRefCount( ref pDb.pCollateNeeded );
}
pDb.pCollateNeeded = TCL.Tcl_DuplicateObj( objv[2] );
TCL.Tcl_IncrRefCount( pDb.pCollateNeeded );
sqlite3_collation_needed( pDb.db, (object)pDb, (dxCollNeeded)tclCollateNeeded );
break;
}
 
/* $db commit_hook ?CALLBACK?
**
** Invoke the given callback just before committing every SQL transaction.
** If the callback throws an exception or returns non-zero, then the
** transaction is aborted. If CALLBACK is an empty string, the callback
** is disabled.
*/
case (int)DB_enum.DB_COMMIT_HOOK:
{
if ( objc > 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
return TCL.TCL_ERROR;
}
else if ( objc == 2 )
{
if ( pDb.zCommit != null )
{
TCL.Tcl_AppendResult( interp, pDb.zCommit );
}
}
else
{
string zCommit;
int len = 0;
if ( pDb.zCommit != null )
{
TCL.Tcl_Free( ref pDb.zCommit );
}
zCommit = TCL.Tcl_GetStringFromObj( objv[2], out len );
if ( zCommit != null && len > 0 )
{
pDb.zCommit = zCommit;// TCL.Tcl_Alloc( len + 1 );
//memcpy( pDb.zCommit, zCommit, len + 1 );
}
else
{
pDb.zCommit = null;
}
if ( pDb.zCommit != null )
{
pDb.interp = interp;
sqlite3_commit_hook( pDb.db, DbCommitHandler, pDb );
}
else
{
sqlite3_commit_hook( pDb.db, null, null );
}
}
break;
}
 
/* $db complete SQL
**
** Return TRUE if SQL is a complete SQL statement. Return FALSE if
** additional lines of input are needed. This is similar to the
** built-in "info complete" command of Tcl.
*/
case (int)DB_enum.DB_COMPLETE:
{
#if !SQLITE_OMIT_COMPLETE
Tcl_Obj pResult;
int isComplete;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL" );
return TCL.TCL_ERROR;
}
isComplete = sqlite3_complete( TCL.Tcl_GetStringFromObj( objv[2], 0 ) );
pResult = TCL.Tcl_GetObjResult( interp );
TCL.Tcl_SetBooleanObj( pResult, isComplete );
#endif
break;
}
 
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
**
** Copy data into table from filename, optionally using SEPARATOR
** as column separators. If a column contains a null string, or the
** value of NULLINDICATOR, a NULL is inserted for the column.
** conflict-algorithm is one of the sqlite conflict algorithms:
** rollback, abort, fail, ignore, replace
** On success, return the number of lines processed, not necessarily same
** as 'db changes' due to conflict-algorithm selected.
**
** This code is basically an implementation/enhancement of
** the sqlite3 shell.c ".import" command.
**
** This command usage is equivalent to the sqlite2.x COPY statement,
** which imports file data into a table using the PostgreSQL COPY file format:
** $db copy $conflit_algo $table_name $filename \t \\N
*/
case (int)DB_enum.DB_COPY:
{
string zTable; /* Insert data into this table */
string zFile; /* The file from which to extract data */
string zConflict; /* The conflict algorithm to use */
sqlite3_stmt pStmt = null; /* A statement */
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
int i, j; /* Loop counters */
int nSep; /* Number of bytes in zSep[] */
int nNull; /* Number of bytes in zNull[] */
StringBuilder zSql = new StringBuilder( 200 ); /* An SQL statement */
string zLine; /* A single line of input from the file */
string[] azCol; /* zLine[] broken up into columns */
string zCommit; /* How to commit changes */
TextReader _in; /* The input file */
int lineno = 0; /* Line number of input file */
StringBuilder zLineNum = new StringBuilder( 80 ); /* Line number print buffer */
Tcl_Obj pResult; /* interp result */
 
string zSep;
string zNull;
if ( objc < 5 || objc > 7 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv,
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?" );
return TCL.TCL_ERROR;
}
if ( objc >= 6 )
{
zSep = TCL.Tcl_GetStringFromObj( objv[5], 0 );
}
else
{
zSep = "\t";
}
if ( objc >= 7 )
{
zNull = TCL.Tcl_GetStringFromObj( objv[6], 0 );
}
else
{
zNull = "";
}
zConflict = TCL.Tcl_GetStringFromObj( objv[2], 0 );
zTable = TCL.Tcl_GetStringFromObj( objv[3], 0 );
zFile = TCL.Tcl_GetStringFromObj( objv[4], 0 );
nSep = strlen30( zSep );
nNull = strlen30( zNull );
if ( nSep == 0 )
{
TCL.Tcl_AppendResult( interp, "Error: non-null separator required for copy" );
return TCL.TCL_ERROR;
}
if ( zConflict != "rollback" &&
zConflict != "abort" &&
zConflict != "fail" &&
zConflict != "ignore" &&
zConflict != "replace" )
{
TCL.Tcl_AppendResult( interp, "Error: \"", zConflict,
"\", conflict-algorithm must be one of: rollback, " +
"abort, fail, ignore, or replace", 0 );
return TCL.TCL_ERROR;
}
zSql.Append( sqlite3_mprintf( "SELECT * FROM '%q'", zTable ) );
if ( zSql == null )
{
TCL.Tcl_AppendResult( interp, "Error: no such table: ", zTable );
return TCL.TCL_ERROR;
}
nByte = strlen30( zSql );
rc = sqlite3_prepare( pDb.db, zSql.ToString(), -1, ref pStmt, 0 );
sqlite3DbFree( null, ref zSql );
if ( rc != 0 )
{
TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
nCol = 0;
}
else
{
nCol = sqlite3_column_count( pStmt );
}
sqlite3_finalize( pStmt );
if ( nCol == 0 )
{
return TCL.TCL_ERROR;
}
//zSql.Append(malloc( nByte + 50 + nCol*2 );
//if( zSql==0 ) {
// TCL.Tcl_AppendResult(interp, "Error: can't malloc()");
// return TCL.TCL_ERROR;
//}
sqlite3_snprintf( nByte + 50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
zConflict, zTable );
j = strlen30( zSql );
for ( i = 1; i < nCol; i++ )
{
//zSql+=[j++] = ',';
//zSql[j++] = '?';
zSql.Append( ",?" );
}
//zSql[j++] = ')';
//zSql[j] = "";
zSql.Append( ")" );
rc = sqlite3_prepare( pDb.db, zSql.ToString(), -1, ref pStmt, 0 );
//free(zSql);
if ( rc != 0 )
{
TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
sqlite3_finalize( pStmt );
return TCL.TCL_ERROR;
}
_in = new StreamReader( zFile );//fopen(zFile, "rb");
if ( _in == null )
{
TCL.Tcl_AppendResult( interp, "Error: cannot open file: ", zFile );
sqlite3_finalize( pStmt );
return TCL.TCL_ERROR;
}
azCol = new string[nCol + 1];//malloc( sizeof(azCol[0])*(nCol+1) );
if ( azCol == null )
{
TCL.Tcl_AppendResult( interp, "Error: can't malloc()" );
_in.Close();//fclose(_in);
return TCL.TCL_ERROR;
}
sqlite3_exec( pDb.db, "BEGIN", 0, 0, 0 );
zCommit = "COMMIT";
while ( ( zLine = _in.ReadLine() ) != null )//local_getline(0, _in))!=0 )
{
string z;
i = 0;
lineno++;
azCol = zLine.Split( zSep[0] );
//for(i=0, z=zLine; *z; z++){
// if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
// *z = 0;
// i++;
// if( i<nCol ){
// azCol[i] = z[nSep];
// z += nSep-1;
// }
// }
//}
if ( azCol.Length != nCol )
{
StringBuilder zErr = new StringBuilder( 200 );
int nErr = strlen30( zFile ) + 200;
//zErr = malloc(nErr);
//if( zErr ){
sqlite3_snprintf( nErr, zErr,
"Error: %s line %d: expected %d columns of data but found %d",
zFile, lineno, nCol, i + 1 );
TCL.Tcl_AppendResult( interp, zErr );
// free(zErr);
//}
zCommit = "ROLLBACK";
break;
}
for ( i = 0; i < nCol; i++ )
{
/* check for null data, if so, bind as null */
if ( ( nNull > 0 && azCol[i] == zNull )
|| strlen30( azCol[i] ) == 0
)
{
sqlite3_bind_null( pStmt, i + 1 );
}
else
{
sqlite3_bind_text( pStmt, i + 1, azCol[i], -1, SQLITE_STATIC );
}
}
sqlite3_step( pStmt );
rc = sqlite3_reset( pStmt );
//free(zLine);
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, "Error: ", sqlite3_errmsg( pDb.db ) );
zCommit = "ROLLBACK";
break;
}
}
//free(azCol);
_in.Close();// fclose( _in );
sqlite3_finalize( pStmt );
sqlite3_exec( pDb.db, zCommit, 0, 0, 0 );
 
if ( zCommit[0] == 'C' )
{
/* success, set result as number of lines processed */
pResult = TCL.Tcl_GetObjResult( interp );
TCL.Tcl_SetIntObj( pResult, lineno );
rc = TCL.TCL_OK;
}
else
{
/* failure, append lineno where failed */
sqlite3_snprintf( 80, zLineNum, "%d", lineno );
TCL.Tcl_AppendResult( interp, ", failed while processing line: ", zLineNum );
rc = TCL.TCL_ERROR;
}
break;
}
 
/*
** $db enable_load_extension BOOLEAN
**
** Turn the extension loading feature on or off. It if off by
** default.
*/
case (int)DB_enum.DB_ENABLE_LOAD_EXTENSION:
{
#if !SQLITE_OMIT_LOAD_EXTENSION
bool onoff = false;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "BOOLEAN" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[2], out onoff ) )
{
return TCL.TCL_ERROR;
}
sqlite3_enable_load_extension( pDb.db, onoff ? 1 : 0 );
break;
#else
TCL.Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
0);
return TCL.TCL_ERROR;
#endif
}
 
/*
** $db errorcode
**
** Return the numeric error code that was returned by the most recent
** call to sqlite3_exec().
*/
case (int)DB_enum.DB_ERRORCODE:
{
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_errcode( pDb.db ) ) );
break;
}
 
/*
** $db exists $sql
** $db onecolumn $sql
**
** The onecolumn method is the equivalent of:
** lindex [$db eval $sql] 0
*/
case (int)DB_enum.DB_EXISTS:
case (int)DB_enum.DB_ONECOLUMN:
{
DbEvalContext sEval = new DbEvalContext();
;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL" );
return TCL.TCL_ERROR;
}
dbEvalInit( sEval, pDb, objv[2], null );
rc = dbEvalStep( sEval );
if ( choice == (int)DB_enum.DB_ONECOLUMN )
{
if ( rc == TCL.TCL_OK )
{
TCL.Tcl_SetObjResult( interp, dbEvalColumnValue( sEval, 0 ) );
}
}
else if ( rc == TCL.TCL_BREAK || rc == TCL.TCL_OK )
{
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( ( rc == TCL.TCL_OK ? 1 : 0 ) ) );
}
dbEvalFinalize( sEval );
 
if ( rc == TCL.TCL_BREAK )
{
rc = TCL.TCL_OK;
}
break;
}
 
/*
** $db eval $sql ?array? ?{ ...code... }?
**
** The SQL statement in $sql is evaluated. For each row, the values are
** placed in elements of the array named "array" and ...code... is executed.
** If "array" and "code" are omitted, then no callback is every invoked.
** If "array" is an empty string, then the values are placed in variables
** that have the same name as the fields extracted by the query.
*/
case (int)DB_enum.DB_EVAL:
{
if ( objc < 3 || objc > 5 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?" );
return TCL.TCL_ERROR;
}
 
if ( objc == 3 )
{
DbEvalContext sEval = new DbEvalContext();
Tcl_Obj pRet = TCL.Tcl_NewObj();
TCL.Tcl_IncrRefCount( pRet );
dbEvalInit( sEval, pDb, objv[2], null );
//Console.WriteLine( objv[2].ToString() );
while ( TCL.TCL_OK == ( rc = dbEvalStep( sEval ) ) )
{
int i;
int nCol;
TclObject[] pDummy;
dbEvalRowInfo( sEval, out nCol, out pDummy );
for ( i = 0; i < nCol; i++ )
{
TCL.Tcl_ListObjAppendElement( interp, pRet, dbEvalColumnValue( sEval, i ) );
}
}
dbEvalFinalize( sEval );
if ( rc == TCL.TCL_BREAK )
{
TCL.Tcl_SetObjResult( interp, pRet );
rc = TCL.TCL_OK;
}
TCL.Tcl_DecrRefCount( ref pRet );
}
else
{
cd = new object[2];
DbEvalContext p;
Tcl_Obj pArray = null;
Tcl_Obj pScript;
 
if ( objc == 5 && !String.IsNullOrEmpty( TCL.Tcl_GetString( objv[3] ) ) )
{
pArray = objv[3];
}
pScript = objv[objc - 1];
TCL.Tcl_IncrRefCount( pScript );
 
p = new DbEvalContext();// (DbEvalContext)Tcl_Alloc( sizeof( DbEvalContext ) );
dbEvalInit( p, pDb, objv[2], pArray );
 
( (object[])cd )[0] = p;
( (object[])cd )[1] = pScript;
rc = DbEvalNextCmd( (object[])cd, interp, TCL.TCL_OK );
}
break;
}
 
/*
** $db function NAME [-argcount N] SCRIPT
**
** Create a new SQL function called NAME. Whenever that function is
** called, invoke SCRIPT to evaluate the function.
*/
case (int)DB_enum.DB_FUNCTION:
{
SqlFunc pFunc;
Tcl_Obj pScript;
string zName;
int nArg = -1;
if ( objc == 6 )
{
string z = TCL.Tcl_GetString( objv[3] );
int n = strlen30( z );
if ( n > 2 && z.StartsWith( "-argcount" ) )//strncmp( z, "-argcount", n ) == 0 )
{
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[4], out nArg ) )
return TCL.TCL_ERROR;
if ( nArg < 0 )
{
TCL.Tcl_AppendResult( interp, "number of arguments must be non-negative" );
return TCL.TCL_ERROR;
}
}
pScript = objv[5];
}
else if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "NAME [-argcount N] SCRIPT" );
return TCL.TCL_ERROR;
}
else
{
pScript = objv[3];
}
zName = TCL.Tcl_GetStringFromObj( objv[2], 0 );
pFunc = findSqlFunc( pDb, zName );
if ( pFunc == null )
return TCL.TCL_ERROR;
if ( pFunc.pScript != null )
{
TCL.Tcl_DecrRefCount( ref pFunc.pScript );
}
pFunc.pScript = pScript;
TCL.Tcl_IncrRefCount( pScript );
pFunc.useEvalObjv = safeToUseEvalObjv( interp, pScript );
rc = sqlite3_create_function( pDb.db, zName, nArg, SQLITE_UTF8,
pFunc, tclSqlFunc, null, null );
if ( rc != SQLITE_OK )
{
rc = TCL.TCL_ERROR;
TCL.Tcl_SetResult( interp, sqlite3_errmsg( pDb.db ), TCL.TCL_VOLATILE );
}
break;
}
 
/*
** $db incrblob ?-readonly? ?DB? TABLE COLUMN ROWID
*/
case (int)DB_enum.DB_INCRBLOB:
{
#if SQLITE_OMIT_INCRBLOB
TCL.Tcl_AppendResult( interp, "incrblob not available in this build" );
return TCL.TCL_ERROR;
#else
int isReadonly = 0;
string zDb = "main" ;
string zTable;
string zColumn;
long iRow = 0;
 
/* Check for the -readonly option */
if ( objc > 3 && TCL.Tcl_GetString( objv[2] ) == "-readonly" )
{
isReadonly = 1;
}
 
if ( objc != ( 5 + isReadonly ) && objc != ( 6 + isReadonly ) )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID" );
return TCL.TCL_ERROR;
}
 
if ( objc == ( 6 + isReadonly ) )
{
zDb = TCL.Tcl_GetString( objv[2] ) ;
}
zTable = TCL.Tcl_GetString( objv[objc - 3] );
zColumn = TCL.Tcl_GetString( objv[objc - 2] ) ;
rc = TCL.Tcl_GetWideIntFromObj( interp, objv[objc - 1], out iRow ) ? 1 : 0;
 
if ( rc == TCL.TCL_OK )
{
rc = createIncrblobChannel(
interp, pDb, zDb, zTable, zColumn, iRow, isReadonly
);
}
break;
#endif
}
/*
** $db interrupt
**
** Interrupt the execution of the inner-most SQL interpreter. This
** causes the SQL statement to return an error of SQLITE_INTERRUPT.
*/
case (int)DB_enum.DB_INTERRUPT:
{
sqlite3_interrupt( pDb.db );
break;
}
 
/*
** $db nullvalue ?STRING?
**
** Change text used when a NULL comes back from the database. If ?STRING?
** is not present, then the current string used for NULL is returned.
** If STRING is present, then STRING is returned.
**
*/
case (int)DB_enum.DB_NULLVALUE:
{
if ( objc != 2 && objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "NULLVALUE" );
return TCL.TCL_ERROR;
}
if ( objc == 3 )
{
int len = 0;
string zNull = TCL.Tcl_GetStringFromObj( objv[2], out len );
if ( pDb.zNull != null )
{
TCL.Tcl_Free( ref pDb.zNull );
}
if ( zNull != null && len > 0 )
{
pDb.zNull = zNull;
//pDb.zNull = TCL.Tcl_Alloc( len + 1 );
//memcpy(pDb->zNull, zNull, len);
//pDb.zNull[len] = '\0';
}
else
{
pDb.zNull = null;
}
}
TCL.Tcl_SetObjResult( interp, dbTextToObj( pDb.zNull ) );
break;
}
 
/*
** $db last_insert_rowid
**
** Return an integer which is the ROWID for the most recent insert.
*/
case (int)DB_enum.DB_LAST_INSERT_ROWID:
{
Tcl_Obj pResult;
Tcl_WideInt rowid;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
return TCL.TCL_ERROR;
}
rowid = sqlite3_last_insert_rowid( pDb.db );
pResult = TCL.Tcl_GetObjResult( interp );
TCL.Tcl_SetLongObj( pResult, rowid );
break;
}
 
/*
** The DB_ONECOLUMN method is implemented together with DB_EXISTS.
*/
 
/* $db progress ?N CALLBACK?
**
** Invoke the given callback every N virtual machine opcodes while executing
** queries.
*/
case (int)DB_enum.DB_PROGRESS:
{
if ( objc == 2 )
{
if ( !String.IsNullOrEmpty( pDb.zProgress ) )
{
TCL.Tcl_AppendResult( interp, pDb.zProgress );
}
}
else if ( objc == 4 )
{
string zProgress;
int len = 0;
int N = 0;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out N ) )
{
return TCL.TCL_ERROR;
};
if ( !String.IsNullOrEmpty( pDb.zProgress ) )
{
TCL.Tcl_Free( ref pDb.zProgress );
}
zProgress = TCL.Tcl_GetStringFromObj( objv[3], len );
if ( !String.IsNullOrEmpty( zProgress ) )
{
//pDb.zProgress = TCL.Tcl_Alloc( len + 1 );
//memcpy( pDb.zProgress, zProgress, len + 1 );
pDb.zProgress = zProgress;
}
else
{
pDb.zProgress = null;
}
#if !SQLITE_OMIT_PROGRESS_CALLBACK
if ( !String.IsNullOrEmpty( pDb.zProgress ) )
{
pDb.interp = interp;
sqlite3_progress_handler( pDb.db, N, DbProgressHandler, pDb );
}
else
{
sqlite3_progress_handler( pDb.db, 0, null, 0 );
}
#endif
}
else
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "N CALLBACK" );
return TCL.TCL_ERROR;
}
break;
}
 
/* $db profile ?CALLBACK?
**
** Make arrangements to invoke the CALLBACK routine after each SQL statement
** that has run. The text of the SQL and the amount of elapse time are
** appended to CALLBACK before the script is run.
*/
case (int)DB_enum.DB_PROFILE:
{
if ( objc > 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
return TCL.TCL_ERROR;
}
else if ( objc == 2 )
{
if ( !String.IsNullOrEmpty( pDb.zProfile ) )
{
TCL.Tcl_AppendResult( interp, pDb.zProfile );
}
}
else
{
string zProfile;
int len = 0;
if ( !String.IsNullOrEmpty( pDb.zProfile ) )
{
TCL.Tcl_Free( ref pDb.zProfile );
}
zProfile = TCL.Tcl_GetStringFromObj( objv[2], out len );
if ( !String.IsNullOrEmpty( zProfile ) && len > 0 )
{
//pDb.zProfile = TCL.Tcl_Alloc( len + 1 );
//memcpy( pDb.zProfile, zProfile, len + 1 );
pDb.zProfile = zProfile;
}
else
{
pDb.zProfile = null;
}
#if !SQLITE_OMIT_TRACE && !(SQLITE_OMIT_FLOATING_POINT)
if ( !String.IsNullOrEmpty( pDb.zProfile ) )
{
pDb.interp = interp;
sqlite3_profile( pDb.db, DbProfileHandler, pDb );
}
else
{
sqlite3_profile( pDb.db, null, null );
}
#endif
}
break;
}
 
/*
** $db rekey KEY
**
** Change the encryption key on the currently open database.
*/
case (int)DB_enum.DB_REKEY:
{
int nKey = 0;
string pKey;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "KEY" );
return TCL.TCL_ERROR;
}
pKey = TCL.Tcl_GetStringFromObj( objv[2], out nKey );
#if SQLITE_HAS_CODEC
rc = sqlite3_rekey( pDb.db, pKey, nKey );
if ( rc != 0 )
{
TCL.Tcl_AppendResult( interp, sqlite3ErrStr( rc ) );
rc = TCL.TCL_ERROR;
}
#endif
break;
}
 
/* $db restore ?DATABASE? FILENAME
**
** Open a database file named FILENAME. Transfer the content
** of FILENAME into the local database DATABASE (default: "main").
*/
case (int)DB_enum.DB_RESTORE:
{
string zSrcFile;
string zDestDb;
sqlite3 pSrc = null;
sqlite3_backup pBackup;
int nTimeout = 0;
 
if ( objc == 3 )
{
zDestDb = "main";
zSrcFile = TCL.Tcl_GetString( objv[2] );
}
else if ( objc == 4 )
{
zDestDb = TCL.Tcl_GetString( objv[2] );
zSrcFile = TCL.Tcl_GetString( objv[3] );
}
else
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "?DATABASE? FILENAME" );
return TCL.TCL_ERROR;
}
rc = sqlite3_open_v2( zSrcFile, out pSrc, SQLITE_OPEN_READONLY, null );
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, "cannot open source database: ",
sqlite3_errmsg( pSrc ) );
sqlite3_close( pSrc );
return TCL.TCL_ERROR;
}
pBackup = sqlite3_backup_init( pDb.db, zDestDb, pSrc, "main" );
if ( pBackup == null )
{
TCL.Tcl_AppendResult( interp, "restore failed: ",
sqlite3_errmsg( pDb.db ) );
sqlite3_close( pSrc );
return TCL.TCL_ERROR;
}
 
#if SQLITE_HAS_CODEC
if ( pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec != null )
{
pBackup.pSrc.pBt.pPager.xCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodec;
pBackup.pSrc.pBt.pPager.xCodecFree = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecFree;
pBackup.pSrc.pBt.pPager.xCodecSizeChng = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecSizeChng;
pBackup.pSrc.pBt.pPager.pCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec.Copy();
if ( pBackup.pDest.GetHashCode() != pBackup.pDestDb.aDb[0].GetHashCode() ) // Not Main Database
{
pBackup.pDest.pBt.pPager.xCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodec;
pBackup.pDest.pBt.pPager.xCodecFree = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecFree;
pBackup.pDest.pBt.pPager.xCodecSizeChng = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.xCodecSizeChng;
pBackup.pDest.pBt.pPager.pCodec = pBackup.pDestDb.aDb[0].pBt.pBt.pPager.pCodec.Copy();
}
}
#endif
while ( ( rc = sqlite3_backup_step( pBackup, 100 ) ) == SQLITE_OK
|| rc == SQLITE_BUSY )
{
if ( rc == SQLITE_BUSY )
{
if ( nTimeout++ >= 3 )
break;
sqlite3_sleep( 100 );
}
}
sqlite3_backup_finish( pBackup );
if ( rc == SQLITE_DONE )
{
rc = TCL.TCL_OK;
}
else if ( rc == SQLITE_BUSY || rc == SQLITE_LOCKED )
{
TCL.Tcl_AppendResult( interp, "restore failed: source database busy"
);
rc = TCL.TCL_ERROR;
}
else
{
TCL.Tcl_AppendResult( interp, "restore failed: ",
sqlite3_errmsg( pDb.db ) );
rc = TCL.TCL_ERROR;
}
sqlite3_close( pSrc );
break;
}
 
/*
** $db status (step|sort|autoindex)
**
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
** SQLITE_STMTSTATUS_SORT for the most recent eval.
*/
case (int)DB_enum.DB_STATUS:
{
int v;
string zOp;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "(step|sort|autoindex)" );
return TCL.TCL_ERROR;
}
zOp = TCL.Tcl_GetString( objv[2] );
if ( zOp == "step" )
{
v = pDb.nStep;
}
else if ( zOp == "sort" )
{
v = pDb.nSort;
}
else if ( zOp == "autoindex" )
{
v = pDb.nIndex;
}
else
{
TCL.Tcl_AppendResult( interp, "bad argument: should be autoindex, step or sort" );
return TCL.TCL_ERROR;
}
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( v ) );
break;
}
 
/*
** $db timeout MILLESECONDS
**
** Delay for the number of milliseconds specified when a file is locked.
*/
case (int)DB_enum.DB_TIMEOUT:
{
int ms = 0;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "MILLISECONDS" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out ms ) )
return TCL.TCL_ERROR;
sqlite3_busy_timeout( pDb.db, ms );
break;
}
 
/*
** $db total_changes
**
** Return the number of rows that were modified, inserted, or deleted
** since the database handle was created.
*/
case (int)DB_enum.DB_TOTAL_CHANGES:
{
Tcl_Obj pResult;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "" );
return TCL.TCL_ERROR;
}
pResult = TCL.Tcl_GetObjResult( interp );
TCL.Tcl_SetIntObj( pResult, sqlite3_total_changes( pDb.db ) );
break;
}
 
/* $db trace ?CALLBACK?
**
** Make arrangements to invoke the CALLBACK routine for each SQL statement
** that is executed. The text of the SQL is appended to CALLBACK before
** it is executed.
*/
case (int)DB_enum.DB_TRACE:
{
if ( objc > 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "?CALLBACK?" );
return TCL.TCL_ERROR;
}
else if ( objc == 2 )
{
if ( pDb.zTrace != null )
{
TCL.Tcl_AppendResult( interp, pDb.zTrace );
}
}
else
{
string zTrace;
int len = 0;
if ( pDb.zTrace != null )
{
TCL.Tcl_Free( ref pDb.zTrace );
}
zTrace = TCL.Tcl_GetStringFromObj( objv[2], out len );
if ( zTrace != null && len > 0 )
{
//pDb.zTrace = TCL.Tcl_Alloc( len + 1 );
pDb.zTrace = zTrace;//memcpy( pDb.zTrace, zTrace, len + 1 );
}
else
{
pDb.zTrace = null;
}
#if !SQLITE_OMIT_TRACE && !(SQLITE_OMIT_FLOATING_POINT)
if ( pDb.zTrace != null )
{
pDb.interp = interp;
sqlite3_trace( pDb.db, (dxTrace)DbTraceHandler, pDb );
}
else
{
sqlite3_trace( pDb.db, null, null );
}
#endif
}
break;
}
 
// /* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
// **
// ** Start a new transaction (if we are not already in the midst of a
// ** transaction) and execute the TCL script SCRIPT. After SCRIPT
// ** completes, either commit the transaction or roll it back if SCRIPT
// ** throws an exception. Or if no new transation was started, do nothing.
// ** pass the exception on up the stack.
// **
// ** This command was inspired by Dave Thomas's talk on Ruby at the
// ** 2005 O'Reilly Open Source Convention (OSCON).
// */
case (int)DB_enum.DB_TRANSACTION:
{
Tcl_Obj pScript;
string zBegin = "SAVEPOINT _tcl_transaction";
if ( objc != 3 && objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "[TYPE] SCRIPT" );
return TCL.TCL_ERROR;
}
if ( pDb.nTransaction == 0 && objc == 4 )
{
string[] TTYPE_strs = { "deferred", "exclusive", "immediate", null };
 
int ttype = 0;
if ( TCL.Tcl_GetIndexFromObj( interp, objv[2], TTYPE_strs, "transaction type",
0, out ttype ) )
{
return TCL.TCL_ERROR;
}
switch ( ttype )
{
case (int)TTYPE_enum.TTYPE_DEFERRED: /* no-op */
;
break;
case (int)TTYPE_enum.TTYPE_EXCLUSIVE:
zBegin = "BEGIN EXCLUSIVE";
break;
case (int)TTYPE_enum.TTYPE_IMMEDIATE:
zBegin = "BEGIN IMMEDIATE";
break;
}
}
pScript = objv[objc - 1];
 
/* Run the SQLite BEGIN command to open a transaction or savepoint. */
pDb.disableAuth++;
rc = sqlite3_exec( pDb.db, zBegin, 0, 0, 0 );
pDb.disableAuth--;
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, sqlite3_errmsg( pDb.db ) );
return TCL.TCL_ERROR;
}
pDb.nTransaction++;
/* If using NRE, schedule a callback to invoke the script pScript, then
** a second callback to commit (or rollback) the transaction or savepoint
** opened above. If not using NRE, evaluate the script directly, then
** call function DbTransPostCmd() to commit (or rollback) the transaction
** or savepoint. */
if ( DbUseNre() )
{
Debugger.Break();
//Tcl_NRAddCallback( interp, DbTransPostCmd, cd, 0, 0, 0 );
//Tcl_NREvalObj(interp, pScript, 0);
}
else
{
rc = DbTransPostCmd( cd, interp, TCL.Tcl_EvalObjEx( interp, pScript, 0 ) );
}
break;
}
 
/*
** $db unlock_notify ?script?
*/
case (int)DB_enum.DB_UNLOCK_NOTIFY:
{
#if !SQLITE_ENABLE_UNLOCK_NOTIFY
TCL.Tcl_AppendResult( interp, "unlock_notify not available in this build", 0 );
rc = TCL.TCL_ERROR;
#else
if( objc!=2 && objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?");
rc = TCL.Tcl_ERROR;
}else{
void (*xNotify)(void **, int) = 0;
void *pNotifyArg = 0;
 
if( pDb.pUnlockNotify ){
Tcl_DecrRefCount(pDb.pUnlockNotify);
pDb.pUnlockNotify = 0;
}
 
if( objc==3 ){
xNotify = DbUnlockNotify;
pNotifyArg = (void )pDb;
pDb.pUnlockNotify = objv[2];
Tcl_IncrRefCount(pDb.pUnlockNotify);
}
 
if( sqlite3_unlock_notify(pDb.db, xNotify, pNotifyArg) ){
Tcl_AppendResult(interp, sqlite3_errmsg(pDb.db), 0);
rc = TCL.Tcl_ERROR;
}
}
#endif
break;
}
/*
** $db wal_hook ?script?
** $db update_hook ?script?
** $db rollback_hook ?script?
*/
case (int)DB_enum.DB_WAL_HOOK:
case (int)DB_enum.DB_UPDATE_HOOK:
case (int)DB_enum.DB_ROLLBACK_HOOK:
{
 
/* set ppHook to point at pUpdateHook or pRollbackHook, depending on
** whether [$db update_hook] or [$db rollback_hook] was invoked.
*/
Tcl_Obj ppHook;
if ( choice == (int)DB_enum.DB_UPDATE_HOOK )
{
ppHook = pDb.pUpdateHook;
}
else if ( choice == (int)DB_enum.DB_WAL_HOOK )
{
ppHook = pDb.pWalHook;
}
else
{
ppHook = pDb.pRollbackHook;
}
 
if ( objc != 2 && objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "?SCRIPT?" );
return TCL.TCL_ERROR;
}
if ( ppHook != null )
{
TCL.Tcl_SetObjResult( interp, ppHook );
if ( objc == 3 )
{
TCL.Tcl_DecrRefCount( ref ppHook );
ppHook = null;
}
}
if ( objc == 3 )
{
Debug.Assert( null == ppHook );
if ( objv[2] != null )//TCL.Tcl_GetCharLength( objv[2] ) > 0 )
{
ppHook = objv[2];
TCL.Tcl_IncrRefCount( ppHook );
}
}
if ( choice == (int)DB_enum.DB_UPDATE_HOOK )
{
pDb.pUpdateHook = ppHook;
}
else
{
pDb.pRollbackHook = ppHook;
}
sqlite3_update_hook( pDb.db, ( pDb.pUpdateHook != null ? (dxUpdateCallback)DbUpdateHandler : null ), pDb );
sqlite3_rollback_hook( pDb.db, ( pDb.pRollbackHook != null ? (dxRollbackCallback)DbRollbackHandler : null ), pDb );
sqlite3_wal_hook( pDb.db, ( pDb.pWalHook != null ? (dxWalCallback)DbWalHandler : null ), pDb );
 
break;
}
 
/* $db version
**
** Return the version string for this database.
*/
case (int)DB_enum.DB_VERSION:
{
TCL.Tcl_SetResult( interp, sqlite3_libversion(), TCL.TCL_STATIC );
break;
}
 
default:
Debug.Assert( false, "Missing switch:" + objv[1].ToString() );
break;
} /* End of the SWITCH statement */
return rc;
}
 
#if SQLITE_TCL_NRE
/*
** Adaptor that provides an objCmd interface to the NRE-enabled
** interface implementation.
*/
static int DbObjCmdAdaptor(
void *cd,
Tcl_Interp interp,
int objc,
Tcl_Obj *const*objv
){
return TCL.TCL_NRCallObjProc(interp, DbObjCmd, cd, objc, objv);
}
#endif //* SQLITE_TCL_NRE */
/*
** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN?
** ?-create BOOLEAN? ?-nomutex BOOLEAN?
**
** This is the main Tcl command. When the "sqlite" Tcl command is
** invoked, this routine runs to process that command.
**
** The first argument, DBNAME, is an arbitrary name for a new
** database connection. This command creates a new command named
** DBNAME that is used to control that connection. The database
** connection is deleted when the DBNAME command is deleted.
**
** The second argument is the name of the database file.
**
*/
static int DbMain( object cd, Tcl_Interp interp, int objc, Tcl_Obj[] objv )
{
SqliteDb p;
string pKey = null;
int nKey = 0;
string zArg;
string zErrMsg;
int i;
string zFile;
string zVfs = null;
int flags;
Tcl_DString translatedFilename;
/* In normal use, each TCL interpreter runs in a single thread. So
** by default, we can turn of mutexing on SQLite database connections.
** However, for testing purposes it is useful to have mutexes turned
** on. So, by default, mutexes default off. But if compiled with
** SQLITE_TCL_DEFAULT_FULLMUTEX then mutexes default on.
*/
#if SQLITE_TCL_DEFAULT_FULLMUTEX
flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
#else
flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX;
#endif
if ( objc == 2 )
{
zArg = TCL.Tcl_GetStringFromObj( objv[1], 0 );
if ( zArg == "-version" )
{
TCL.Tcl_AppendResult( interp, sqlite3_version, null );
return TCL.TCL_OK;
}
if ( zArg == "-has-codec" )
{
#if SQLITE_HAS_CODEC
TCL.Tcl_AppendResult( interp, "1" );
#else
TCL.Tcl_AppendResult( interp, "0", null );
#endif
return TCL.TCL_OK;
}
if ( zArg == "-tcl-uses-utf" )
{
TCL.Tcl_AppendResult( interp, "1", null );
return TCL.TCL_OK;
}
}
for ( i = 3; i + 1 < objc; i += 2 )
{
zArg = TCL.Tcl_GetString( objv[i] );
if ( zArg == "-key" )
{
pKey = TCL.Tcl_GetStringFromObj( objv[i + 1], out nKey );
}
else if ( zArg == "-vfs" )
{
zVfs = TCL.Tcl_GetString( objv[i + 1] );
}
else if ( zArg == "-readonly" )
{
bool b = false;
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
return TCL.TCL_ERROR;
if ( b )
{
flags &= ~( SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE );
flags |= SQLITE_OPEN_READONLY;
}
else
{
flags &= ~SQLITE_OPEN_READONLY;
flags |= SQLITE_OPEN_READWRITE;
}
}
else if ( zArg == "-create" )
{
bool b = false;
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
return TCL.TCL_ERROR;
if ( b && ( flags & SQLITE_OPEN_READONLY ) == 0 )
{
flags |= SQLITE_OPEN_CREATE;
}
else
{
flags &= ~SQLITE_OPEN_CREATE;
}
}
else if ( zArg == "-nomutex" )
{
bool b = false;
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
return TCL.TCL_ERROR;
if ( b )
{
flags |= SQLITE_OPEN_NOMUTEX;
flags &= ~SQLITE_OPEN_FULLMUTEX;
}
else
{
flags &= ~SQLITE_OPEN_NOMUTEX;
}
}
else if ( zArg == "-fullmutex" )//strcmp( zArg, "-fullmutex" ) == 0 )
{
bool b = false;
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[i + 1], out b ) )
return TCL.TCL_ERROR;
if ( b )
{
flags |= SQLITE_OPEN_FULLMUTEX;
flags &= ~SQLITE_OPEN_NOMUTEX;
}
else
{
flags &= ~SQLITE_OPEN_FULLMUTEX;
}
}
else
{
TCL.Tcl_AppendResult( interp, "unknown option: ", zArg, null );
return TCL.TCL_ERROR;
}
}
if ( objc < 3 || ( objc & 1 ) != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv,
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN?"
#if SQLITE_HAS_CODEC
+ " ?-key CODECKEY?"
#endif
);
return TCL.TCL_ERROR;
}
zErrMsg = "";
p = new SqliteDb();//(SqliteDb)Tcl_Alloc( sizeof(*p) );
if ( p == null )
{
TCL.Tcl_SetResult( interp, "malloc failed", TCL.TCL_STATIC );
return TCL.TCL_ERROR;
}
//memset(p, 0, sizeof(*p));
zFile = TCL.Tcl_GetStringFromObj( objv[2], 0 );
//zFile = TCL.Tcl_TranslateFileName( interp, zFile, ref translatedFilename );
sqlite3_open_v2( zFile, out p.db, flags, zVfs );
//Tcl_DStringFree( ref translatedFilename );
if ( SQLITE_OK != sqlite3_errcode( p.db ) )
{
zErrMsg = sqlite3_errmsg( p.db );// sqlite3_mprintf( "%s", sqlite3_errmsg( p.db ) );
sqlite3_close( p.db );
p.db = null;
}
#if SQLITE_HAS_CODEC
if ( p.db != null )
{
sqlite3_key( p.db, pKey, nKey );
}
#endif
if ( p.db == null )
{
TCL.Tcl_SetResult( interp, zErrMsg, TCL.TCL_VOLATILE );
TCL.Tcl_Free( ref p );
zErrMsg = "";// sqlite3DbFree( db, ref zErrMsg );
return TCL.TCL_ERROR;
}
p.maxStmt = NUM_PREPARED_STMTS;
p.interp = interp;
zArg = TCL.Tcl_GetStringFromObj( objv[1], 0 );
if ( DbUseNre() )
{
Debugger.Break();
//Tcl_NRCreateCommand(interp, zArg, DbObjCmdAdaptor, DbObjCmd,
// p, DbDeleteCmd);
}
else
{
TCL.Tcl_CreateObjCommand( interp, zArg, (Interp.dxObjCmdProc)DbObjCmd, p, (Interp.dxCmdDeleteProc)DbDeleteCmd );
}
return TCL.TCL_OK;
}
 
/*
** Provide a dummy TCL.Tcl_InitStubs if we are using this as a static
** library.
*/
#if !USE_TCL_STUBS
//# undef TCL.Tcl_InitStubs
static void Tcl_InitStubs( Tcl_Interp interp, string s, int i )
{
}
#endif
 
/*
** Make sure we have a PACKAGE_VERSION macro defined. This will be
** defined automatically by the TEA makefile. But other makefiles
** do not define it.
*/
#if !PACKAGE_VERSION
public static string PACKAGE_VERSION;//# define PACKAGE_VERSION SQLITE_VERSION
#endif
 
 
/*
** Initialize this module.
**
** This Tcl module contains only a single new Tcl command named "sqlite".
** (Hence there is no namespace. There is no point in using a namespace
** if the extension only supplies one new name!) The "sqlite" command is
** used to open a new SQLite database. See the DbMain() routine above
** for additional information.
**
** The EXTERN macros are required by TCL in order to work on windows.
*/
//int Sqlite3_Init(Tcl_Interp interp){
static public int Sqlite3_Init( Tcl_Interp interp )
{
PACKAGE_VERSION = SQLITE_VERSION;
Tcl_InitStubs( interp, "tclsharp 8.4", 0 );
TCL.Tcl_CreateObjCommand( interp, "sqlite3", (Interp.dxObjCmdProc)DbMain, null, null );
TCL.Tcl_PkgProvide( interp, "sqlite3", PACKAGE_VERSION );
 
#if !SQLITE_3_SUFFIX_ONLY
/* The "sqlite" alias is undocumented. It is here only to support
** legacy scripts. All new scripts should use only the "sqlite3"
** command.
*/
TCL.Tcl_CreateObjCommand( interp, "sqlite", (Interp.dxObjCmdProc)DbMain, null, null );
#endif
return TCL.TCL_OK;
}
//int Tclsqlite3_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
//int Sqlite3_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
//int Tclsqlite3_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
//int Sqlite3_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
//int Tclsqlite3_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
//int Sqlite3_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
//int Tclsqlite3_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK;}
 
 
#if !SQLITE_3_SUFFIX_ONLY
//int Sqlite_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
//int Tclsqlite_Init(Tcl_Interp interp){ return Sqlite3_Init(interp); }
//int Sqlite_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
//int Tclsqlite_SafeInit(Tcl_Interp interp){ return TCL.TCL_OK; }
//int Sqlite_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
//int Tclsqlite_Unload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
//int Sqlite_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK; }
//int Tclsqlite_SafeUnload(Tcl_Interp interp, int flags){ return TCL.TCL_OK;}
#endif
 
#if TCLSH
/*****************************************************************************
** All of the code that follows is used to build standalone TCL interpreters
** that are statically linked with SQLite. Enable these by compiling
** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard
** tclsh but with SQLite built in. An n of 2 generates the SQLite space
** analysis program.
*/
 
#if (SQLITE_TEST) || (SQLITE_TCLMD5)
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
 
/*
* If compiled on a machine that doesn't have a 32-bit integer,
* you just set "uint32" to the appropriate datatype for an
* unsigned 32-bit integer. For example:
*
* cc -Duint32='unsigned long' md5.c
*
*/
//#if !uint32
//# define uint32 unsigned int
//#endif
 
//struct MD5Context {
// int isInit;
// uint32 buf[4];
// uint32 bits[2];
// unsigned char in[64];
//};
//typedef struct MD5Context MD5Context;
class MD5Context
{
public bool isInit;
public u32[] buf = new u32[4];
public u32[] bits = new u32[2];
public u32[] _in = new u32[64];
public Mem _Mem;
};
 
/*
* Note: this code is harmless on little-endian machines.
*/
//static void byteReverse (unsigned char *buf, unsigned longs){
// uint32 t;
// do {
// t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
// ((unsigned)buf[1]<<8 | buf[0]);
// *(uint32 )buf = t;
// buf += 4;
// } while (--longs);
//}
 
/* The four core functions - F1 is optimized somewhat */
 
delegate u32 dxF1234( u32 x, u32 y, u32 z );
 
//* #define F1(x, y, z) (x & y | ~x & z) */
//#define F1(x, y, z) (z ^ (x & (y ^ z)))
static u32 F1( u32 x, u32 y, u32 z )
{
return ( z ^ ( x & ( y ^ z ) ) );
}
 
//#define F2(x, y, z) F1(z, x, y)
static u32 F2( u32 x, u32 y, u32 z )
{
return F1( z, x, y );
}
 
//#define F3(x, y, z) (x ^ y ^ z)
static u32 F3( u32 x, u32 y, u32 z )
{
return ( x ^ y ^ z );
}
 
//#define F4(x, y, z) (y ^ (x | ~z))
static u32 F4( u32 x, u32 y, u32 z )
{
return ( y ^ ( x | ~z ) );
}
 
///* This is the central step in the MD5 algorithm. */
//#define MD5STEP(f, w, x, y, z, data, s) \
// ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
static void MD5STEP( dxF1234 f, ref u32 w, u32 x, u32 y, u32 z, u32 data, byte s )
{
w += f( x, y, z ) + data;
w = w << s | w >> ( 32 - s );
w += x;
}
 
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
static void MD5Transform( u32[] buf, u32[] _in )
{
u32 a, b, c, d;
 
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
 
MD5STEP( F1, ref a, b, c, d, _in[0] + 0xd76aa478, 7 );
MD5STEP( F1, ref d, a, b, c, _in[1] + 0xe8c7b756, 12 );
MD5STEP( F1, ref c, d, a, b, _in[2] + 0x242070db, 17 );
MD5STEP( F1, ref b, c, d, a, _in[3] + 0xc1bdceee, 22 );
MD5STEP( F1, ref a, b, c, d, _in[4] + 0xf57c0faf, 7 );
MD5STEP( F1, ref d, a, b, c, _in[5] + 0x4787c62a, 12 );
MD5STEP( F1, ref c, d, a, b, _in[6] + 0xa8304613, 17 );
MD5STEP( F1, ref b, c, d, a, _in[7] + 0xfd469501, 22 );
MD5STEP( F1, ref a, b, c, d, _in[8] + 0x698098d8, 7 );
MD5STEP( F1, ref d, a, b, c, _in[9] + 0x8b44f7af, 12 );
MD5STEP( F1, ref c, d, a, b, _in[10] + 0xffff5bb1, 17 );
MD5STEP( F1, ref b, c, d, a, _in[11] + 0x895cd7be, 22 );
MD5STEP( F1, ref a, b, c, d, _in[12] + 0x6b901122, 7 );
MD5STEP( F1, ref d, a, b, c, _in[13] + 0xfd987193, 12 );
MD5STEP( F1, ref c, d, a, b, _in[14] + 0xa679438e, 17 );
MD5STEP( F1, ref b, c, d, a, _in[15] + 0x49b40821, 22 );
 
MD5STEP( F2, ref a, b, c, d, _in[1] + 0xf61e2562, 5 );
MD5STEP( F2, ref d, a, b, c, _in[6] + 0xc040b340, 9 );
MD5STEP( F2, ref c, d, a, b, _in[11] + 0x265e5a51, 14 );
MD5STEP( F2, ref b, c, d, a, _in[0] + 0xe9b6c7aa, 20 );
MD5STEP( F2, ref a, b, c, d, _in[5] + 0xd62f105d, 5 );
MD5STEP( F2, ref d, a, b, c, _in[10] + 0x02441453, 9 );
MD5STEP( F2, ref c, d, a, b, _in[15] + 0xd8a1e681, 14 );
MD5STEP( F2, ref b, c, d, a, _in[4] + 0xe7d3fbc8, 20 );
MD5STEP( F2, ref a, b, c, d, _in[9] + 0x21e1cde6, 5 );
MD5STEP( F2, ref d, a, b, c, _in[14] + 0xc33707d6, 9 );
MD5STEP( F2, ref c, d, a, b, _in[3] + 0xf4d50d87, 14 );
MD5STEP( F2, ref b, c, d, a, _in[8] + 0x455a14ed, 20 );
MD5STEP( F2, ref a, b, c, d, _in[13] + 0xa9e3e905, 5 );
MD5STEP( F2, ref d, a, b, c, _in[2] + 0xfcefa3f8, 9 );
MD5STEP( F2, ref c, d, a, b, _in[7] + 0x676f02d9, 14 );
MD5STEP( F2, ref b, c, d, a, _in[12] + 0x8d2a4c8a, 20 );
 
MD5STEP( F3, ref a, b, c, d, _in[5] + 0xfffa3942, 4 );
MD5STEP( F3, ref d, a, b, c, _in[8] + 0x8771f681, 11 );
MD5STEP( F3, ref c, d, a, b, _in[11] + 0x6d9d6122, 16 );
MD5STEP( F3, ref b, c, d, a, _in[14] + 0xfde5380c, 23 );
MD5STEP( F3, ref a, b, c, d, _in[1] + 0xa4beea44, 4 );
MD5STEP( F3, ref d, a, b, c, _in[4] + 0x4bdecfa9, 11 );
MD5STEP( F3, ref c, d, a, b, _in[7] + 0xf6bb4b60, 16 );
MD5STEP( F3, ref b, c, d, a, _in[10] + 0xbebfbc70, 23 );
MD5STEP( F3, ref a, b, c, d, _in[13] + 0x289b7ec6, 4 );
MD5STEP( F3, ref d, a, b, c, _in[0] + 0xeaa127fa, 11 );
MD5STEP( F3, ref c, d, a, b, _in[3] + 0xd4ef3085, 16 );
MD5STEP( F3, ref b, c, d, a, _in[6] + 0x04881d05, 23 );
MD5STEP( F3, ref a, b, c, d, _in[9] + 0xd9d4d039, 4 );
MD5STEP( F3, ref d, a, b, c, _in[12] + 0xe6db99e5, 11 );
MD5STEP( F3, ref c, d, a, b, _in[15] + 0x1fa27cf8, 16 );
MD5STEP( F3, ref b, c, d, a, _in[2] + 0xc4ac5665, 23 );
 
MD5STEP( F4, ref a, b, c, d, _in[0] + 0xf4292244, 6 );
MD5STEP( F4, ref d, a, b, c, _in[7] + 0x432aff97, 10 );
MD5STEP( F4, ref c, d, a, b, _in[14] + 0xab9423a7, 15 );
MD5STEP( F4, ref b, c, d, a, _in[5] + 0xfc93a039, 21 );
MD5STEP( F4, ref a, b, c, d, _in[12] + 0x655b59c3, 6 );
MD5STEP( F4, ref d, a, b, c, _in[3] + 0x8f0ccc92, 10 );
MD5STEP( F4, ref c, d, a, b, _in[10] + 0xffeff47d, 15 );
MD5STEP( F4, ref b, c, d, a, _in[1] + 0x85845dd1, 21 );
MD5STEP( F4, ref a, b, c, d, _in[8] + 0x6fa87e4f, 6 );
MD5STEP( F4, ref d, a, b, c, _in[15] + 0xfe2ce6e0, 10 );
MD5STEP( F4, ref c, d, a, b, _in[6] + 0xa3014314, 15 );
MD5STEP( F4, ref b, c, d, a, _in[13] + 0x4e0811a1, 21 );
MD5STEP( F4, ref a, b, c, d, _in[4] + 0xf7537e82, 6 );
MD5STEP( F4, ref d, a, b, c, _in[11] + 0xbd3af235, 10 );
MD5STEP( F4, ref c, d, a, b, _in[2] + 0x2ad7d2bb, 15 );
MD5STEP( F4, ref b, c, d, a, _in[9] + 0xeb86d391, 21 );
 
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
 
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
static void MD5Init( MD5Context ctx )
{
ctx.isInit = true;
ctx.buf[0] = 0x67452301;
ctx.buf[1] = 0xefcdab89;
ctx.buf[2] = 0x98badcfe;
ctx.buf[3] = 0x10325476;
ctx.bits[0] = 0;
ctx.bits[1] = 0;
}
 
/*
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
static void MD5Update( MD5Context pCtx, byte[] buf, int len )
{
 
MD5Context ctx = (MD5Context)pCtx;
int t;
 
/* Update bitcount */
 
t = (int)ctx.bits[0];
if ( ( ctx.bits[0] = (u32)( t + ( (u32)len << 3 ) ) ) < t )
ctx.bits[1]++; /* Carry from low to high */
ctx.bits[1] += (u32)( len >> 29 );
 
t = ( t >> 3 ) & 0x3f; /* Bytes already in shsInfo.data */
 
/* Handle any leading odd-sized chunks */
 
int _buf = 0; // Offset into buffer
int p = t; //Offset into ctx._in
if ( t != 0 )
{
//byte p = (byte)ctx._in + t;
t = 64 - t;
if ( len < t )
{
Buffer.BlockCopy( buf, _buf, ctx._in, p, len );// memcpy( p, buf, len );
return;
}
Buffer.BlockCopy( buf, _buf, ctx._in, p, t ); //memcpy( p, buf, t );
//byteReverse(ctx._in, 16);
MD5Transform( ctx.buf, ctx._in );
_buf += t;// buf += t;
len -= t;
}
 
/* Process data in 64-byte chunks */
 
while ( len >= 64 )
{
Buffer.BlockCopy( buf, _buf, ctx._in, 0, 64 );//memcpy( ctx._in, buf, 64 );
//byteReverse(ctx._in, 16);
MD5Transform( ctx.buf, ctx._in );
_buf += 64;// buf += 64;
len -= 64;
}
 
/* Handle any remaining bytes of data. */
 
Buffer.BlockCopy( buf, _buf, ctx._in, 0, len ); //memcpy( ctx._in, buf, len );
}
 
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
 
static void MD5Final( byte[] digest, MD5Context pCtx )
{
MD5Context ctx = pCtx;
int count;
int p;
 
/* Compute number of bytes mod 64 */
count = (int)( ctx.bits[0] >> 3 ) & 0x3F;
 
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = count;
ctx._in[p++] = 0x80;
 
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
 
/* Pad out to 56 mod 64 */
if ( count < 8 )
{
/* Two lots of padding: Pad the first block to 64 bytes */
Array.Clear( ctx._in, p, count );//memset(p, 0, count);
//byteReverse( ctx._in, 16 );
MD5Transform( ctx.buf, ctx._in );
 
/* Now fill the next block with 56 bytes */
Array.Clear( ctx._in, 0, 56 );//memset(ctx._in, 0, 56);
}
else
{
/* Pad block to 56 bytes */
Array.Clear( ctx._in, p, count - 8 );//memset(p, 0, count-8);
}
//byteReverse( ctx._in, 14 );
 
/* Append length in bits and transform */
ctx._in[14] = (byte)ctx.bits[0];
ctx._in[15] = (byte)ctx.bits[1];
 
MD5Transform( ctx.buf, ctx._in );
//byteReverse( ctx.buf, 4 );
Buffer.BlockCopy( ctx.buf, 0, digest, 0, 16 );//memcpy(digest, ctx.buf, 16);
//memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */
Array.Clear( ctx._in, 0, ctx._in.Length );
Array.Clear( ctx.bits, 0, ctx.bits.Length );
Array.Clear( ctx.buf, 0, ctx.buf.Length );
ctx._Mem = null;
}
 
/*
** Convert a 128-bit MD5 digest into a 32-digit base-16 number.
*/
static void DigestToBase16( byte[] digest, byte[] zBuf )
{
string zEncode = "0123456789abcdef";
int i, j;
 
for ( j = i = 0; i < 16; i++ )
{
int a = digest[i];
zBuf[j++] = (byte)zEncode[( a >> 4 ) & 0xf];
zBuf[j++] = (byte)zEncode[a & 0xf];
}
if ( j < zBuf.Length )
zBuf[j] = 0;
}
 
 
/*
** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers
** each representing 16 bits of the digest and separated from each
** other by a "-" character.
*/
//static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
// int i, j;
// unsigned int x;
// for(i=j=0; i<16; i+=2){
// x = digest[i]*256 + digest[i+1];
// if( i>0 ) zDigest[j++] = '-';
// sprintf(&zDigest[j], "%05u", x);
// j += 5;
// }
// zDigest[j] = 0;
//}
 
/*
** A TCL command for md5. The argument is the text to be hashed. The
** Result is the hash in base64.
*/
static int md5_cmd( object cd, Tcl_Interp interp, int argc, Tcl_Obj[] argv )
{
MD5Context ctx = new MD5Context();
byte[] digest = new byte[16];
byte[] zBuf = new byte[32];
 
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" TEXT\"" );
return TCL.TCL_ERROR;
}
MD5Init( ctx );
MD5Update( ctx, Encoding.UTF8.GetBytes( argv[1].ToString() ), Encoding.UTF8.GetByteCount( argv[1].ToString() ) );
MD5Final( digest, ctx );
DigestToBase16( digest, zBuf );
TCL.Tcl_AppendResult( interp, Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ) );
return TCL.TCL_OK;
}
 
 
/*
** A TCL command to take the md5 hash of a file. The argument is the
** name of the file.
*/
static int md5file_cmd( object cd, Tcl_Interp interp, int argc, Tcl_Obj[] argv )
{
StreamReader _in = null;
byte[] digest = new byte[16];
StringBuilder zBuf = new StringBuilder( 10240 );
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FILENAME\"", 0 );
return TCL.TCL_ERROR;
}
Debugger.Break(); // TODO -- _in = fopen( argv[1], "rb" );
if ( _in == null )
{
TCL.Tcl_AppendResult( interp, "unable to open file \"", argv[1],
"\" for reading", 0 );
return TCL.TCL_ERROR;
}
Debugger.Break(); // TODO
//MD5Init( ctx );
//for(;;){
// int n;
// n = fread(zBuf, 1, zBuf.Capacity, _in);
// if( n<=0 ) break;
// MD5Update(ctx, zBuf.ToString(), (unsigned)n);
//}
//fclose(_in);
//MD5Final(digest, ctx);
// DigestToBase16(digest, zBuf);
//Tcl_AppendResult( interp, zBuf );
return TCL.TCL_OK;
}
 
/*
** Register the four new TCL commands for generating MD5 checksums
** with the TCL interpreter.
*/
static public int Md5_Init( Tcl_Interp interp )
{
TCL.Tcl_CreateCommand( interp, "md5", md5_cmd, null, null );
//Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc)md5_cmd,
// MD5DigestToBase10x8, 0);
 
TCL.Tcl_CreateCommand( interp, "md5file", md5file_cmd, null, null );
 
//Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc)md5file_cmd,
// MD5DigestToBase10x8, 0);
return TCL.TCL_OK;
}
#endif //* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */
 
#if (SQLITE_TEST)
/*
** During testing, the special md5sum() aggregate function is available.
** inside SQLite. The following routines implement that function.
*/
static void md5step( sqlite3_context context, int argc, sqlite3_value[] argv )
{
MD5Context p = null;
int i;
if ( argc < 1 )
return;
Mem pMem = sqlite3_aggregate_context( context, 1 );//sizeof(*p));
if ( pMem._MD5Context == null )
{
pMem._MD5Context = new MD5Context();
( (MD5Context)pMem._MD5Context )._Mem = pMem;
}
p = (MD5Context)pMem._MD5Context;
if ( p == null )
return;
if ( !p.isInit )
{
MD5Init( p );
}
for ( i = 0; i < argc; i++ )
{
byte[] zData = sqlite3_value_text( argv[i] ) == null ? null : Encoding.UTF8.GetBytes( sqlite3_value_text( argv[i] ) );
if ( zData != null )
{
MD5Update( p, zData, zData.Length );
}
}
}
 
static void md5finalize( sqlite3_context context )
{
MD5Context p;
byte[] digest = new byte[16];
byte[] zBuf = new byte[33];
Mem pMem = sqlite3_aggregate_context( context, 0 );
if ( pMem != null )
{
p = (MD5Context)pMem._MD5Context;
MD5Final( digest, p );
}
DigestToBase16( digest, zBuf );
sqlite3_result_text( context, Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ), -1, SQLITE_TRANSIENT );
}
 
static int Md5_Register( sqlite3 db, ref string dummy1, sqlite3_api_routines dummy2 )
{
int rc = sqlite3_create_function( db, "md5sum", -1, SQLITE_UTF8, 0, null,
md5step, md5finalize );
sqlite3_overload_function( db, "md5sum", -1 ); /* To exercise this API */
return rc;
}
 
#endif //* defined(SQLITE_TEST) */
 
 
/*
** If the macro TCLSH is one, then put in code this for the
** "main" routine that will initialize Tcl and take input from
** standard input, or if a file is named on the command line
** the TCL interpreter reads and evaluates that file.
*/
#if TCLSH//==1
//static char zMainloop[] =
// "set line {}\n"
// "while {![eof stdin]} {\n"
// "if {$line!=\"\"} {\n"
// "puts -nonewline \"> \"\n"
// "} else {\n"
// "puts -nonewline \"% \"\n"
// "}\n"
// "flush stdout\n"
// "append line [gets stdin]\n"
// "if {[info complete $line]} {\n"
// "if {[catch {uplevel #0 $line} result]} {\n"
// "puts stderr \"Error: $result\"\n"
// "} elseif {$result!=\"\"} {\n"
// "puts $result\n"
// "}\n"
// "set line {}\n"
// "} else {\n"
// "append line \\n\n"
// "}\n"
// "}\n"
//;
#endif
 
//#if TCLSH==2
//static char zMainloop[] =
//#include "spaceanal_tcl.h"
//;
//#endif
//#define TCLSH_MAIN main /* Needed to fake out mktclapp */
#if SQLITE_TEST
//static void init_all(Tcl_Interp );
static int init_all_cmd(
ClientData cd,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
 
Tcl_Interp slave;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SLAVE" );
return TCL.TCL_ERROR;
}
 
slave = null;// TCL.Tcl_GetSlave( interp, TCL.Tcl_GetString( objv[1] ) );
if ( slave == null )
{
return TCL.TCL_ERROR;
}
 
init_all( slave );
return TCL.TCL_OK;
}
#endif
 
/*
** Configure the interpreter passed as the first argument to have access
** to the commands and linked variables that make up:
**
** * the [sqlite3] extension itself,
**
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
**
** * If SQLITE_TEST is set, the various test interfaces used by the Tcl
** test suite.
*/
static void init_all( Tcl_Interp interp )
{
Sqlite3_Init( interp );
#if (SQLITE_TEST) || (SQLITE_TCLMD5)
Md5_Init( interp );
#endif
#if SQLITE_TEST
//{
//extern int Sqliteconfig_Init(Tcl_Interp);
//extern int Sqlitetest1_Init(Tcl_Interp);
//extern int Sqlitetest2_Init(Tcl_Interp);
//extern int Sqlitetest3_Init(Tcl_Interp);
//extern int Sqlitetest4_Init(Tcl_Interp);
//extern int Sqlitetest5_Init(Tcl_Interp);
//extern int Sqlitetest6_Init(Tcl_Interp);
//extern int Sqlitetest7_Init(Tcl_Interp);
//extern int Sqlitetest8_Init(Tcl_Interp);
//extern int Sqlitetest9_Init(Tcl_Interp);
//extern int Sqlitetestasync_Init(Tcl_Interp);
//extern int Sqlitetest_autoext_Init(Tcl_Interp);
//extern int Sqlitetest_demovfs_Init(Tcl_Interp );
//extern int Sqlitetest_func_Init(Tcl_Interp);
//extern int Sqlitetest_hexio_Init(Tcl_Interp);
//extern int Sqlitetest_malloc_Init(Tcl_Interp);
//extern int Sqlitetest_mutex_Init(Tcl_Interp);
//extern int Sqlitetestschema_Init(Tcl_Interp);
//extern int Sqlitetestsse_Init(Tcl_Interp);
//extern int Sqlitetesttclvar_Init(Tcl_Interp);
//extern int SqlitetestThread_Init(Tcl_Interp);
//extern int SqlitetestOnefile_Init();
//extern int SqlitetestOsinst_Init(Tcl_Interp);
//extern int Sqlitetestbackup_Init(Tcl_Interp);
//extern int Sqlitetestintarray_Init(Tcl_Interp);
//extern int Sqlitetestvfs_Init(Tcl_Interp );
//extern int SqlitetestStat_Init(Tcl_Interp);
//extern int Sqlitetestrtree_Init(Tcl_Interp);
//extern int Sqlitequota_Init(Tcl_Interp);
//extern int Sqlitemultiplex_Init(Tcl_Interp);
//extern int SqliteSuperlock_Init(Tcl_Interp);
//extern int SqlitetestSyscall_Init(Tcl_Interp);
//extern int Sqlitetestfuzzer_Init(Tcl_Interp);
//extern int Sqlitetestwholenumber_Init(Tcl_Interp);
 
#if (SQLITE_ENABLE_FTS3) || (SQLITE_ENABLE_FTS4)
//extern int Sqlitetestfts3_Init(Tcl_Interp interp);
#endif
 
#if SQLITE_ENABLE_ZIPVFS
// extern int Zipvfs_Init(Tcl_Interp);
// Zipvfs_Init(interp);
#endif
 
Sqliteconfig_Init( interp );
Sqlitetest1_Init( interp );
Sqlitetest2_Init( interp );
Sqlitetest3_Init( interp );
 
//Threads not implemented under C#
//Sqlitetest4_Init(interp);
 
//TODO implemented under C#
//Sqlitetest5_Init(interp);
 
//Simulated Crashtests not implemented under C#
//Sqlitetest6_Init(interp);
 
//client/server version (Unix Only) not implemented under C#
//Sqlitetest7_Init(interp);
 
//virtual table interface not implemented under C#
//Sqlitetest8_Init(interp);
 
Sqlitetest9_Init( interp );
 
//asynchronous IO extension interface not implemented under C#
//Sqlitetestasync_Init(interp);
 
//sqlite3_auto_extension() function not implemented under C#
//Sqlitetest_autoext_Init(interp);
 
//VFS not implemented under C#
//Sqlitetest_demovfs_Init(interp);
 
Sqlitetest_func_Init( interp );
Sqlitetest_hexio_Init( interp );
Sqlitetest_malloc_Init( interp );
Sqlitetest_mutex_Init( interp );
 
//virtual table interfaces not implemented under C#
//Sqlitetestschema_Init(interp);
 
//virtual table interfaces not implemented under C#
//Sqlitetesttclvar_Init(interp);
 
//Threads not implemented under C#
//SqlitetestThread_Init(interp);
 
//VFS not implemented under C#
//SqlitetestOnefile_Init(interp);
 
//VFS not implemented under C#
//SqlitetestOsinst_Init(interp);
 
Sqlitetestbackup_Init( interp );
 
//virtual table interfaces not implemented under C#
//Sqlitetestintarray_Init(interp);
 
//VFS not implemented under C#
//Sqlitetestvfs_Init(interp);
 
//virtual table interfaces not implemented under C#
//SqlitetestStat_Init(interp);
//Sqlitetestrtree_Init( interp );
//Sqlitequota_Init( interp );
//Sqlitemultiplex_Init( interp );
//SqliteSuperlock_Init( interp );
//SqlitetestSyscall_Init( interp );
Sqlitetestfuzzer_Init( interp );
//Sqlitetestwholenumber_Init( interp );
 
#if (SQLITE_ENABLE_FTS3) || (SQLITE_ENABLE_FTS4)
//Sqlitetestfts3_Init(interp);
#endif
TCL.Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, null );
 
#if SQLITE_SSE
Sqlitetestsse_Init(interp);
#endif
}
#endif
}
 
#if FALSE
//#define TCLSH_MAIN main /* Needed to fake out mktclapp */
int TCLSH_MAIN(int argc, char **argv){
Tcl_Interp interp;
 
/* Call sqlite3_shutdown() once before doing anything else. This is to
** test that sqlite3_shutdown() can be safely called by a process before
** sqlite3_initialize() is. */
sqlite3_shutdown();
 
#if TCLSH//TCLSH==2
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
#endif
Tcl_FindExecutable(argv[0]);
 
interp = TCL.Tcl_CreateInterp();
init_all(interp);
if( argc>=2 ){
int i;
char zArgc[32];
sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
for(i=3-TCLSH; i<argc; i++){
Tcl_SetVar(interp, "argv", argv[i],
TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
}
if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
string zInfo = TCL.Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
if( zInfo==0 ) zInfo = TCL.Tcl_GetStringResult(interp);
fprintf(stderr,"%s: %s\n", *argv, zInfo);
return 1;
}
}
if( TCLSH==2 || argc<=1 ){
Tcl_GlobalEval(interp, zMainloop);
}
return 0;
}
#endif
#endif // * TCLSH */
#endif // NO_TCL
}
 
/trunk/testfixture/src/test1_c.cs
@@ -0,0 +1,6843 @@
using System;
using System.Diagnostics;
using System.Text;
 
using i64 = System.Int64;
using u32 = System.UInt32;
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using ClientData = System.Object;
using sqlite3_int64 = System.Int64;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_u3264 = System.UInt64;
using sqlite3_value = Sqlite3.Mem;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
public partial class Sqlite3
{
/*
** 2001 September 15
**
** 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.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
 
/*
** This is a copy of the first part of the SqliteDb structure in
** tclsqlite.c. We need it here so that the get_sqlite_pointer routine
** can extract the sqlite3* pointer from an existing Tcl SQLite
** connection.
*/
//struct SqliteDb {
// sqlite3 db=null;
//};
 
/*
** Convert text generated by the "%p" conversion format back into
** a pointer.
*/
static int testHexToInt( int h )
{
if ( h >= '0' && h <= '9' )
{
return h - '0';
}
else if ( h >= 'a' && h <= 'f' )
{
return h - 'a' + 10;
}
else
{
Debug.Assert( h >= 'A' && h <= 'F' );
return h - 'A' + 10;
}
}
static object sqlite3TestTextToPtr( Tcl_Interp interp, string z )
{
//object p ;
//var v = new u64[1];
//u32 v2;
//int zIndex = 0;
//if ( z[0] == '0' && z[1] == 'x' )
//{
// zIndex += 2;
//}
//v[0] = 0;
//while ( zIndex < z.Length )* z )
//{
// v[0] = ( v[0] << 4 ) + (ulong)testHexToInt( z[zIndex] );
// zIndex++;
//}
//if ( sizeof( object ) == sizeof( u64 ) )
//{
// Marshal.Copy( v, 0, (IntPtr)p, 1 );// memcpy( &p, v, sizeof( p ) );
//}
//else
//{
// Debug.Assert( sizeof( p ) == sizeof( v2 ) );
// v2 = (u32)v;
// memcpy( &p, v2, sizeof( p ) );
//}
WrappedCommand cmdInfo = new WrappedCommand();
if ( TCL.Tcl_GetCommandInfo( interp, z, out cmdInfo ) || cmdInfo == null )
{
return null;
}
else
{
return cmdInfo.objClientData;
}
}
 
 
/*
** A TCL command that returns the address of the sqlite* pointer
** for an sqlite connection instance. Bad things happen if the
** input is not an sqlite connection.
*/
static int get_sqlite_pointer(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
SqliteDb p;
WrappedCommand cmdInfo = null;
//string zBuf ;//[100];
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SQLITE-CONNECTION" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetCommandInfo( interp, objv[1].ToString(), out cmdInfo ) )
{
TCL.Tcl_AppendResult( interp, "command not found: ",
TCL.Tcl_GetString( objv[1] ), null );
return TCL.TCL_ERROR;
}
//p = (SqliteDb)cmdInfo.objclientdata;
//zBuf = p.db.GetHashCode().ToString();
//sqlite3_snprintf( zBuf, "%p", p.db );
//if( strncmp(zBuf,"0x",2) ){
// sqlite3_snprintf(zBuf, "0x%p", p.db);
//}
//TCL.Tcl_AppendResult(interp, zBuf,null );
TCL.Tcl_AppendResult( interp, objv[1].ToString() );
return TCL.TCL_OK;
}
 
/*
** Decode a pointer to an sqlite3 object.
*/
static int getDbPointer( Tcl_Interp interp, string zA, out sqlite3 ppDb )
{
SqliteDb p;
WrappedCommand cmdInfo = new WrappedCommand();
if ( !TCL.Tcl_GetCommandInfo( interp, zA, out cmdInfo ) )
{
if ( cmdInfo == null )
{
ppDb = new sqlite3();
}
else
{
p = (SqliteDb)cmdInfo.objClientData;
ppDb = p.db;
}
}
else
{
ppDb = null;
}
return TCL.TCL_OK;
}
 
 
static string sqlite3TestErrorName( int rc )
{
string zName = "";
switch ( rc )
{
case SQLITE_OK:
zName = "SQLITE_OK";
break;
case SQLITE_ERROR:
zName = "SQLITE_ERROR";
break;
case SQLITE_INTERNAL:
zName = "SQLITE_INTERNAL";
break;
case SQLITE_PERM:
zName = "SQLITE_PERM";
break;
case SQLITE_ABORT:
zName = "SQLITE_ABORT";
break;
case SQLITE_BUSY:
zName = "SQLITE_BUSY";
break;
case SQLITE_LOCKED:
zName = "SQLITE_LOCKED";
break;
case SQLITE_LOCKED_SHAREDCACHE:
zName = "SQLITE_LOCKED_SHAREDCACHE";
break;
case SQLITE_NOMEM:
zName = "SQLITE_NOMEM";
break;
case SQLITE_READONLY:
zName = "SQLITE_READONLY";
break;
case SQLITE_INTERRUPT:
zName = "SQLITE_INTERRUPT";
break;
case SQLITE_IOERR:
zName = "SQLITE_IOERR";
break;
case SQLITE_CORRUPT:
zName = "SQLITE_CORRUPT";
break;
case SQLITE_NOTFOUND:
zName = "SQLITE_NOTFOUND";
break;
case SQLITE_FULL:
zName = "SQLITE_FULL";
break;
case SQLITE_CANTOPEN:
zName = "SQLITE_CANTOPEN";
break;
case SQLITE_PROTOCOL:
zName = "SQLITE_PROTOCOL";
break;
case SQLITE_EMPTY:
zName = "SQLITE_EMPTY";
break;
case SQLITE_SCHEMA:
zName = "SQLITE_SCHEMA";
break;
case SQLITE_TOOBIG:
zName = "SQLITE_TOOBIG";
break;
case SQLITE_CONSTRAINT:
zName = "SQLITE_CONSTRAINT";
break;
case SQLITE_MISMATCH:
zName = "SQLITE_MISMATCH";
break;
case SQLITE_MISUSE:
zName = "SQLITE_MISUSE";
break;
case SQLITE_NOLFS:
zName = "SQLITE_NOLFS";
break;
case SQLITE_AUTH:
zName = "SQLITE_AUTH";
break;
case SQLITE_FORMAT:
zName = "SQLITE_FORMAT";
break;
case SQLITE_RANGE:
zName = "SQLITE_RANGE";
break;
case SQLITE_NOTADB:
zName = "SQLITE_NOTADB";
break;
case SQLITE_ROW:
zName = "SQLITE_ROW";
break;
case SQLITE_DONE:
zName = "SQLITE_DONE";
break;
case SQLITE_IOERR_READ:
zName = "SQLITE_IOERR_READ";
break;
case SQLITE_IOERR_SHORT_READ:
zName = "SQLITE_IOERR_SHORT_READ";
break;
case SQLITE_IOERR_WRITE:
zName = "SQLITE_IOERR_WRITE";
break;
case SQLITE_IOERR_FSYNC:
zName = "SQLITE_IOERR_FSYNC";
break;
case SQLITE_IOERR_DIR_FSYNC:
zName = "SQLITE_IOERR_DIR_FSYNC";
break;
case SQLITE_IOERR_TRUNCATE:
zName = "SQLITE_IOERR_TRUNCATE";
break;
case SQLITE_IOERR_FSTAT:
zName = "SQLITE_IOERR_FSTAT";
break;
case SQLITE_IOERR_UNLOCK:
zName = "SQLITE_IOERR_UNLOCK";
break;
case SQLITE_IOERR_RDLOCK:
zName = "SQLITE_IOERR_RDLOCK";
break;
case SQLITE_IOERR_DELETE:
zName = "SQLITE_IOERR_DELETE";
break;
case SQLITE_IOERR_BLOCKED:
zName = "SQLITE_IOERR_BLOCKED";
break;
case SQLITE_IOERR_NOMEM:
zName = "SQLITE_IOERR_NOMEM";
break;
case SQLITE_IOERR_ACCESS:
zName = "SQLITE_IOERR_ACCESS";
break;
case SQLITE_IOERR_CHECKRESERVEDLOCK:
zName = "SQLITE_IOERR_CHECKRESERVEDLOCK";
break;
case SQLITE_IOERR_LOCK:
zName = "SQLITE_IOERR_LOCK";
break;
case SQLITE_CORRUPT_VTAB:
zName = "SQLITE_CORRUPT_VTAB";
break;
case SQLITE_READONLY_RECOVERY:
zName = "SQLITE_READONLY_RECOVERY";
break;
case SQLITE_READONLY_CANTLOCK:
zName = "SQLITE_READONLY_CANTLOCK";
break;
default:
zName = "SQLITE_Unknown";
break;
}
return zName;
}
//#define t1ErrorName sqlite3TestErrorName
static string t1ErrorName( int i )
{
return sqlite3TestErrorName( i );
}
/*
** Convert an sqlite3_stmt* into an sqlite3*. This depends on the
** fact that the sqlite3* is the first field in the Vdbe structure.
*/
//#define StmtToDb(X) sqlite3_db_handle(X)
static sqlite3 StmtToDb( Vdbe v )
{
return sqlite3_db_handle( v );
}
 
/*
** Check a return value to make sure it agrees with the results
** from sqlite3_errcode.
*/
static int sqlite3TestErrCode( Tcl_Interp interp, sqlite3 db, int rc )
{
if ( sqlite3_threadsafe() == 0 && rc != SQLITE_MISUSE && rc != SQLITE_OK
&& sqlite3_errcode( db ) != rc )
{
StringBuilder zBuf = new StringBuilder( 200 );//char zBuf[200];
int r2 = sqlite3_errcode( db );
sqlite3_snprintf( 200, zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)",
sqlite3TestErrorName( rc ), rc, sqlite3TestErrorName( r2 ), r2 );//t1ErrorName( rc ), rc, t1ErrorName( r2 ), r2 );
TCL.Tcl_ResetResult( interp );
TCL.Tcl_AppendResult( interp, zBuf.ToString() );
return 1;
}
return 0;
}
 
/*
** Decode a pointer to an sqlite3_stmt object.
*/
static int getStmtPointer(
Tcl_Interp interp,
string zArg,
out sqlite3_stmt ppStmt
)
{
ppStmt = (sqlite3_stmt)sqlite3TestTextToPtr( interp, zArg );
WrappedCommand cmdInfo = new WrappedCommand();
TCL.Tcl_GetCommandInfo( interp, zArg, out cmdInfo );
ppStmt = cmdInfo == null ? null : (sqlite3_stmt)cmdInfo.objClientData;
 
return TCL.TCL_OK;
}
 
/*
** Generate a text representation of a pointer that can be understood
** by the getDbPointer and getVmPointer routines above.
**
** The problem is, on some machines (Solaris) if you do a printf with
** "%p" you cannot turn around and do a scanf with the same "%p" and
** get your pointer back. You have to prepend a "0x" before it will
** work. Or at least that is what is reported to me (drh). But this
** behavior varies from machine to machine. The solution used her is
** to test the string right after it is generated to see if it can be
** understood by scanf, and if not, try prepending an "0x" to see if
** that helps. If nothing works, a fatal error is generated.
*/
/*
** Decode a pointer to an sqlite3_stmt object.
*/
 
 
static int sqlite3TestMakePointerStr( Tcl_Interp interp, StringBuilder zPtr, object p )
{
sqlite3_snprintf( 100, zPtr, "->%p", p );
if ( TCL.Tcl_CreateCommandPointer( interp, zPtr, p ) )
{
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
/*
** The callback routine for sqlite3_exec_printf().
*/
static int exec_printf_cb( object pArg, sqlite3_int64 argc, object p2, object p3 )
{
string[] name = (string[])p3;
string[] argv = (string[])p2;
TclObject str = (TclObject)pArg;
int i;
 
if ( TCL.Tcl_DStringLength( str ) == 0 )
{
for ( i = 0; i < argc; i++ )
{
TCL.Tcl_DStringAppendElement( str, name[i] != null ? name[i] + " " : "NULL " );
}
}
string beginbrace = "", endbrace = "";
for ( i = 0; i < argc; i++ )
{
if ( argc > 1 )
{
if ( Util.scanElement( null, argv[i].ToString() ) != 0 )
{
beginbrace = "{";
endbrace = "}";
}
else
{
beginbrace = "";
endbrace = "";
}
}
TCL.Tcl_DStringAppendElement( str, argv[i] != null ? beginbrace + argv[i] + endbrace + ( i < argc - 1 ? " " : "" ) : "NULL" );
}
return 0;
}
 
/*
** The I/O tracing callback.
*/
#if !(SQLITE_OMIT_TRACE) && TRACE
//static FILE *iotrace_file = 0;
//static void io_trace_callback(string zFormat, ...){
// va_list ap;
// va_start(ap, zFormat);
// vfprintf(iotrace_file, zFormat, ap);
// va_end(ap);
// fflush(iotrace_file);
//}
#endif
 
/*
** Usage: io_trace FILENAME
**
** Turn I/O tracing on or off. If FILENAME is not an empty string,
** I/O tracing begins going into FILENAME. If FILENAME is an empty
** string, I/O tracing is turned off.
*/
//static int test_io_trace(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// Tcl_Obj[] argv /* Text of each argument */
//){
#if !(SQLITE_OMIT_TRACE) && (TRACE)
// if( argc!=2 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " FILENAME\"", 0);
// return TCL.TCL_ERROR;
// }
// if( iotrace_file ){
// if( iotrace_file!=stdout && iotrace_file!=stderr ){
// fclose(iotrace_file);
// }
// iotrace_file = 0;
// sqlite3IoTrace = 0;
// }
// if( argv[1][0] ){
// if( strcmp(argv[1],"stdout")==0 ){
// iotrace_file = stdout;
// }else if( strcmp(argv[1],"stderr")==0 ){
// iotrace_file = stderr;
// }else{
// iotrace_file = fopen(argv[1], "w");
// }
// sqlite3IoTrace = io_trace_callback;
// }
#endif
// return TCL.TCL_OK;
//}
 
 
/*
** Usage: sqlite3_exec_printf DB FORMAT STRING
**
** Invoke the sqlite3_exec_printf() interface using the open database
** DB. The SQL is the string FORMAT. The format string should contain
** one %s or %q. STRING is the value inserted into %s or %q.
*/
static int test_exec_printf(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
TclObject str = null;
int rc;
string zErr = "";
string zSql = "";
StringBuilder zBuf = new StringBuilder( 30 );
if ( argc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB FORMAT STRING" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_DStringInit( out str );
zSql = sqlite3_mprintf( argv[2].ToString(), argv[3].ToString() );
rc = sqlite3_exec( db, zSql, (dxCallback)exec_printf_cb, str, ref zErr );
sqlite3DbFree( db, ref zSql );
sqlite3_snprintf( 30, zBuf, "%d", rc );
TCL.Tcl_AppendElement( interp, zBuf );
TCL.Tcl_AppendElement( interp, rc == SQLITE_OK ? str.ToString() : zErr ); //TCL.Tcl_DStringValue(ref str)
TCL.Tcl_DStringFree( ref str );
if ( zErr != null )
sqlite3DbFree( db, ref zErr );
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_exec_hex DB HEX
**
** Invoke the sqlite3_exec() on a string that is obtained by translating
** HEX into ASCII. Most characters are translated as is. %HH becomes
** a hex character.
*/
static int test_exec_hex(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
TclObject str = null;
int rc, i, j;
string zErr = "";
string zHex;
StringBuilder zSql = new StringBuilder( 500 );
string zBuf = "";
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB HEX" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
zHex = argv[2].ToString();
for ( i = j = 0; j < zHex.Length && zHex[j] != 0; i++, j++ )
{
if ( zHex[j] == '%' && zHex[j + 2] != 0 && zHex[j + 2] != 0 )
{
zSql.Append( (char)( ( testHexToInt( zHex[j + 1] ) << 4 ) + testHexToInt( zHex[j + 2] ) ) );
j += 2;
}
else
{
zSql.Append( zHex[j] );
}
}
//zSql[i] = '\0';
TCL.Tcl_DStringInit( out str );
rc = sqlite3_exec( db, zSql.ToString(), (dxCallback)exec_printf_cb, str, ref zErr );
zBuf = rc.ToString();// sprintf( zBuf, "%d", rc );
TCL.Tcl_AppendElement( interp, zBuf );
TCL.Tcl_AppendElement( interp, rc == SQLITE_OK ? str.ToString() : zErr );
TCL.Tcl_DStringFree( ref str );
// //sqlite3_free(ref zErr);
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
return TCL.TCL_OK;
}
 
 
/*
** Usage: db_enter DB
** db_leave DB
**
** Enter or leave the mutex on a database connection.
*/
static int db_enter(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
sqlite3_mutex_enter( db.mutex );
return TCL.TCL_OK;
}
static int db_leave(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
sqlite3_mutex_leave( db.mutex );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_exec DB SQL
**
** Invoke the sqlite3_exec interface using the open database DB
*/
static int test_exec(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
TclObject str = TclString.newInstance( "" );
int rc;
string zErr = "";
string zSql;
int i, j;
StringBuilder zBuf = new StringBuilder( 30 );
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB SQL" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_DStringInit( out str );
zSql = sqlite3_mprintf( "%s", argv[2].ToString() );
StringBuilder sb = new StringBuilder( zSql.Length );
for ( i = 0; i < zSql.Length; i++ )
{
if ( zSql[i] == '%' )
{
sb.Append( (char)( ( testHexToInt( zSql[i + 1] ) << 4 ) + testHexToInt( zSql[i + 2] ) ) );
i += 2;
}
else
sb.Append( zSql[i] );
}
////zSql[j] = 0;
rc = sqlite3_exec( db, sb.ToString(), exec_printf_cb, str, ref zErr );
sqlite3DbFree( db, ref zSql );
sqlite3_snprintf( 30, zBuf, "%d", rc );
TCL.Tcl_AppendElement( interp, zBuf );
TCL.Tcl_AppendElement( interp, rc == SQLITE_OK ? str.ToString() : zErr );
//TCL.Tcl_DStringFree(&str);
if ( zErr != "" )
sqlite3DbFree( db, ref zErr );
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_exec_nr DB SQL
**
** Invoke the sqlite3_exec interface using the open database DB. Discard
** all results
*/
static int test_exec_nr(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
int rc;
string zErr = "";
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB SQL" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_exec( db, argv[2].ToString(), null, null, ref zErr );
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...
**
** Test the %z format of sqlite_mprintf(). Use multiple mprintf() calls to
** concatenate arg0 through argn using separator as the separator.
** Return the result.
*/
static int test_mprintf_z(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
string zResult = "";
int i;
 
for ( i = 2; i < argc && ( i == 2 || zResult != "" ); i++ )
{
zResult = sqlite3_mprintf( "%z%s%s", zResult, argv[1].ToString(), argv[i].ToString() );
}
TCL.Tcl_AppendResult( interp, zResult );
//sqlite3DbFree( db, zResult );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_n_test STRING
**
** Test the %n format of sqlite_mprintf(). Return the length of the
** input string.
*/
static int test_mprintf_n(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
string zStr;
int n = 0;
zStr = sqlite3_mprintf( "%s%n", argv[1].ToString() );
n = zStr.Length;
//sqlite3DbFree( db, zStr );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( n ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_snprintf_int SIZE FORMAT INT
**
** Test the of sqlite3_snprintf() routine. SIZE is the size of the
** output buffer in bytes. The maximum size is 100. FORMAT is the
** format string. INT is a single integer argument. The FORMAT
** string must require no more than this one integer argument. If
** You pass in a format string that requires more than one argument,
** bad things will happen.
*/
static int test_snprintf_int(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
StringBuilder zStr = new StringBuilder( 100 );
int n = atoi( argv[1].ToString() );
string zFormat = argv[2].ToString();
int a1 = atoi( argv[3].ToString() );
if ( n > zStr.Capacity )
n = zStr.Capacity;// sizeof( zStr );
zStr = new StringBuilder( "abcdefghijklmnopqrstuvwxyz" );
sqlite3_snprintf( n, zStr, zFormat, a1 );
TCL.Tcl_AppendResult( interp, zStr );
return TCL.TCL_OK;
}
 
#if !SQLITE_OMIT_GET_TABLE
/*
** Usage: sqlite3_get_table_printf DB FORMAT STRING ?--no-counts?
**
** Invoke the sqlite3_get_table_printf() interface using the open database
** DB. The SQL is the string FORMAT. The format string should contain
** one %s or %q. STRING is the value inserted into %s or %q.
*/
static int test_get_table_printf(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
){
sqlite3 db=null;
TCL.Tcl_DString str;
int rc;
string zErr = 0;
int nRow, nCol;
char **aResult;
int i;
char zBuf[30];
string zSql;
int resCount = -1;
if( argc==5 ){
if( TCL.Tcl_GetInt(interp, argv[4], out resCount) ) return TCL.TCL_ERROR;
}
if( argc!=4 && argc!=5 ){
TCL.Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" DB FORMAT STRING ?COUNT?", 0);
return TCL.TCL_ERROR;
}
if( getDbPointer(interp, argv[1].ToString(), out db) !=0) return TCL.TCL_ERROR;
TCL.Tcl_DStringInit(&str);
zSql = sqlite3_mprintf(argv[2],argv[3]);
if( argc==5 ){
rc = sqlite3_get_table(db, zSql, aResult, 0, 0, zErr);
}else{
rc = sqlite3_get_table(db, zSql, aResult, nRow, nCol, zErr);
resCount = (nRow+1)*nCol;
}
sqlite3DbFree(db,zSql);
sqlite3_snprintf(zBuf, "%d", rc);
TCL.Tcl_AppendElement(interp, zBuf);
if( rc==SQLITE_OK ){
if( argc==4 ){
sqlite3_snprintf(zBuf, "%d", nRow);
TCL.Tcl_AppendElement(interp, zBuf);
sqlite3_snprintf(zBuf, "%d", nCol);
TCL.Tcl_AppendElement(interp, zBuf);
}
for(i=0; i<resCount; i++){
TCL.Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
}
}else{
TCL.Tcl_AppendElement(interp, zErr);
}
//sqlite3_free_table(aResult);
if( zErr ) sqlite3DbFree(db,zErr);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL.TCL_ERROR;
return TCL.TCL_OK;
}
#endif //* SQLITE_OMIT_GET_TABLE*/
 
/*
** Usage: sqlite3_last_insert_rowid DB
**
** Returns the integer ROWID of the most recent insert.
*/
//static int test_last_rowid(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// Tcl_Obj[] argv /* Text of each argument */
//){
// sqlite3 db=null;
// char zBuf[30];
 
// if( argc!=2 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"");
// return TCL.TCL_ERROR;
// }
// if( getDbPointer(interp, argv[1].ToString(), out db) !=0) return TCL.TCL_ERROR;
// sqlite3_snprintf(zBuf, "%lld", sqlite3_last_insert_rowid(db));
// TCL.Tcl_AppendResult(interp, zBuf);
// return SQLITE_OK;
//}
 
/*
** Usage: sqlite3_key DB KEY
**
** Set the codec key.
*/
static int test_key(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
string zKey;
int nKey;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FILENAME\"" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
zKey = argv[2].ToString();
nKey = zKey.Length;
#if SQLITE_HAS_CODEC
sqlite3_key( db, zKey, nKey );
#endif
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_rekey DB KEY
**
** Change the codec key.
*/
static int test_rekey(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
string zKey;
int nKey;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FILENAME\"" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
zKey = argv[2].ToString();
nKey = zKey.Length;
#if SQLITE_HAS_CODEC
sqlite3_rekey( db, zKey, nKey );
#endif
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_close DB
**
** Closes the database opened by sqlite3_open.
*/
static int sqlite_test_close(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
int rc;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FILENAME\"" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_close( db );
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), TCL.TCL_STATIC );
return TCL.TCL_OK;
}
 
/*
** Implementation of the x_coalesce() function.
** Return the first argument non-NULL argument.
*/
static void t1_ifnullFunc(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
int i;
for ( i = 0; i < argc; i++ )
{
if ( SQLITE_NULL != sqlite3_value_type( argv[i] ) )
{
int n = sqlite3_value_bytes( argv[i] );
sqlite3_result_text( context, sqlite3_value_text( argv[i] ),
n, SQLITE_TRANSIENT );
break;
}
}
}
 
/*
** These are test functions. hex8() interprets its argument as
** UTF8 and returns a hex encoding. hex16le() interprets its argument
** as UTF16le and returns a hex encoding.
*/
static void hex8Func( sqlite3_context p, int argc, sqlite3_value[] argv )
{
string z;
int i;
StringBuilder zBuf = new StringBuilder( 200 );
z = sqlite3_value_text( argv[0] );
StringBuilder zTemp = new StringBuilder( 200 );
for ( i = 0; i < zBuf.Capacity / 2 - 2 && i < argv[0].n; i++ )
{
sqlite3_snprintf( 4, zTemp, "%02x", z[i] & 0xff );
zBuf.Append( zTemp );
}
//zBuf[i*2] = 0;
sqlite3_result_text( p, zBuf, -1, SQLITE_TRANSIENT );
}
#if !SQLITE_OMIT_UTF16
static void hex16Func(sqlite3_context p, int argc, sqlite3_value[] argv){
Debugger.Break (); //TODO --
// const unsigned short int *z;
// int i;
// char zBuf[400];
// z = sqlite3_value_text16(argv[0]);
// for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
// sqlite3_snprintf(&zBuf[i*4], "%04x", z[i]&0xff);
// }
// zBuf[i*4] = 0;
// sqlite3_result_text(p, (char)zBuf, -1, SQLITE_TRANSIENT);
}
#endif
 
/*
** A structure into which to accumulate text.
*/
struct dstr
{
public int nAlloc; /* Space allocated */
public int nUsed; /* Space used */
public StringBuilder z; /* The space */
};
 
/*
** Append text to a dstr
*/
static void dstrAppend( dstr p, string z, int divider )
{
int n = z.Length;// strlen( z );
// if( p.nUsed + n + 2 > p.nAlloc ){
// string zNew;
p.nAlloc = p.nAlloc * 2 + n + 200;
p.z.Capacity = p.nAlloc;
// zNew = sqlite3_realloc(p.z, p.nAlloc);
// if( zNew==0 ){
// sqlite3DbFree(db,p.z);
// memset(p, 0, sizeof(*p));
// return;
// }
// p.z = zNew;
// }
// if( divider && p.nUsed>0 ){
// p.z[p.nUsed++] = divider;
// }
// memcpy(p.z[p.nUsed], z, n+1);
p.nUsed += n;
p.z.Append( divider + z );
}
 
/*
** Invoked for each callback from sqlite3ExecFunc
*/
static int execFuncCallback( object pData, sqlite3_int64 argc, object _argv, object NotUsed )
{
Tcl_Obj[] argv = (Tcl_Obj[])_argv;
dstr p = (dstr)pData;
int i;
for ( i = 0; i < argc; i++ )
{
if ( argv[i] == null )
{
dstrAppend( p, "NULL", ' ' );
}
else
{
dstrAppend( p, argv[i].ToString(), ' ' );
}
}
return 0;
}
 
/*
** Implementation of the x_sqlite_exec() function. This function takes
** a single argument and attempts to execute that argument as SQL code.
** This is illegal and should set the SQLITE_MISUSE flag on the database.
**
** 2004-Jan-07: We have changed this to make it legal to call sqlite3_exec()
** from within a function call.
**
** This routine simulates the effect of having two threads attempt to
** use the same database at the same time.
*/
static void sqlite3ExecFunc(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
dstr x = new dstr();
//memset(&x, 0, sizeof(x));
string sDummy = "";
sqlite3_exec( (sqlite3)sqlite3_context_db_handle( context ),
sqlite3_value_text( argv[0] ),
(dxCallback)execFuncCallback, (object)x, ref sDummy );
sqlite3_result_text( context, x.z, x.nUsed, SQLITE_TRANSIENT );
x.z = null;// sqlite3DbFree( db, ref x.z );
}
 
/*
** Implementation of tkt2213func(), a scalar function that takes exactly
** one argument. It has two interesting features:
**
** * It calls sqlite3_value_text() 3 times on the argument sqlite3_value*.
** If the three pointers returned are not the same an SQL error is raised.
**
** * Otherwise it returns a copy of the text representation of its
** argument in such a way as the VDBE representation is a Mem* cell
** with the MEM_Term flag clear.
**
** Ticket #2213 can therefore be tested by evaluating the following
** SQL expression:
**
** tkt2213func(tkt2213func('a string'));
*/
static void tkt2213Function(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
int nText;
string zText1;
string zText2;
string zText3;
 
nText = sqlite3_value_bytes( argv[0] );
zText1 = sqlite3_value_text( argv[0] );
zText2 = sqlite3_value_text( argv[0] );
zText3 = sqlite3_value_text( argv[0] );
 
if ( zText1 != zText2 || zText2 != zText3 )
{
sqlite3_result_error( context, "tkt2213 is not fixed", -1 );
}
else
{
//string zCopy = (char )sqlite3Malloc(nText);
//memcpy(zCopy, zText1, nText);
sqlite3_result_text( context, zText1, nText, null ); //sqlite3_free );
}
}
 
/*
** The following SQL function takes 4 arguments. The 2nd and
** 4th argument must be one of these strings: 'text', 'text16',
** or 'blob' corresponding to API functions
**
** sqlite3_value_text()
** sqlite3_value_text16()
** sqlite3_value_blob()
**
** The third argument is a string, either 'bytes' or 'bytes16' or 'noop',
** corresponding to APIs:
**
** sqlite3_value_bytes()
** sqlite3_value_bytes16()
** noop
**
** The APIs designated by the 2nd through 4th arguments are applied
** to the first argument in order. If the pointers returned by the
** second and fourth are different, this routine returns 1. Otherwise,
** this routine returns 0.
**
** This function is used to test to see when returned pointers from
** the _text(), _text16() and _blob() APIs become invalidated.
*/
static void ptrChngFunction(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
sqlite3_result_int( context, 0 );
return;
//Debugger.Break(); //TODO --
//string p1 = "", p2 = "";
//string zCmd;
//if ( argc != 4 )
// return;
//zCmd = sqlite3_value_text( argv[1] );
//if ( zCmd == null )
// return;
// if( strcmp(zCmd,"text")==0 ){
// p1 = (const void)sqlite3_value_text(argv[0]);
//#if !SQLITE_OMIT_UTF16
// }else if( strcmp(zCmd, "text16")==0 ){
// p1 = (const void)sqlite3_value_text16(argv[0]);
//#endif
// }else if( strcmp(zCmd, "blob")==0 ){
// p1 = (const void)sqlite3_value_blob(argv[0]);
// }else{
// return;
// }
// zCmd = (const char)sqlite3_value_text(argv[2]);
// if( zCmd==0 ) return;
// if( strcmp(zCmd,"bytes")==0 ){
// sqlite3_value_bytes(argv[0]);
//#if !SQLITE_OMIT_UTF16
// }else if( strcmp(zCmd, "bytes16")==0 ){
// sqlite3_value_bytes16(argv[0]);
//#endif
// }else if( strcmp(zCmd, "noop")==0 ){
// /* do nothing */
// }else{
// return;
// }
// zCmd = (const char)sqlite3_value_text(argv[3]);
// if( zCmd==0 ) return;
// if( strcmp(zCmd,"text")==0 ){
// p2 = (const void)sqlite3_value_text(argv[0]);
//#if !SQLITE_OMIT_UTF16
// }else if( strcmp(zCmd, "text16")==0 ){
// p2 = (const void)sqlite3_value_text16(argv[0]);
//#endif
// }else if( strcmp(zCmd, "blob")==0 ){
// p2 = (const void)sqlite3_value_blob(argv[0]);
// }else{
// return;
// }
//sqlite3_result_int( context, p1 != p2 ? 1 : 0 );
}
 
 
/*
** Usage: sqlite_test_create_function DB
**
** Call the sqlite3_create_function API on the given database in order
** to create a function named "x_coalesce". This function does the same thing
** as the "coalesce" function. This function also registers an SQL function
** named "x_sqlite_exec" that invokes sqlite3_exec(). Invoking sqlite3_exec()
** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
** The effect is similar to trying to use the same database connection from
** two threads at the same time.
**
** The original motivation for this routine was to be able to call the
** sqlite3_create_function function while a query is in progress in order
** to test the SQLITE_MISUSE detection logic.
*/
static int test_create_function(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
int rc;
sqlite3 db = null;
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB\"" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_create_function( db, "x_coalesce", -1, SQLITE_ANY, 0,
t1_ifnullFunc, null, null );
if ( rc == SQLITE_OK )
{
rc = sqlite3_create_function( db, "hex8", 1, SQLITE_ANY, 0,
hex8Func, null, null );
}
#if !SQLITE_OMIT_UTF16
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, null, hex16Func, null,null);
}
#endif
if ( rc == SQLITE_OK )
{
rc = sqlite3_create_function( db, "tkt2213func", 1, SQLITE_ANY, 0,
tkt2213Function, null, null );
}
if ( rc == SQLITE_OK )
{
rc = sqlite3_create_function( db, "pointer_change", 4, SQLITE_ANY, 0,
ptrChngFunction, null, null );
}
 
#if !SQLITE_OMIT_UTF16
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
** because it is not tested anywhere else. */
if( rc==SQLITE_OK ){
string zUtf16;
sqlite3_value pVal;
sqlite3_mutex_enter(db.mutex);
pVal = sqlite3ValueNew(db);
sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC);
zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
if( db.mallocFailed !=0{
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_create_function16(db, zUtf16, 1, SQLITE_UTF16, db, sqlite3ExecFunc,null,null );
}
sqlite3ValueFree(ref pVal);
sqlite3_mutex_leave(db.mutex);
}
#endif
 
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), 0 );
return TCL.TCL_OK;
}
 
/*
** Routines to implement the x_count() aggregate function.
**
** x_count() counts the number of non-null arguments. But there are
** some twists for testing purposes.
**
** If the argument to x_count() is 40 then a UTF-8 error is reported
** on the step function. If x_count(41) is seen, then a UTF-16 error
** is reported on the step function. If the total count is 42, then
** a UTF-8 error is reported on the finalize function.
*/
//typedef struct t1CountCtx t1CountCtx;
 
static void t1CountStep(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
SumCtx p;
Mem pMem = sqlite3_aggregate_context( context, 1 );//sizeof(*p));
if ( pMem._SumCtx == null )
pMem._SumCtx = new SumCtx();
p = pMem._SumCtx;
if ( p.Context == null )
p.Context = pMem;
if ( ( argc == 0 || SQLITE_NULL != sqlite3_value_type( argv[0] ) ) && p != null )
{
p.cnt++;
}
if ( argc > 0 )
{
int v = sqlite3_value_int( argv[0] );
if ( v == 40 )
{
sqlite3_result_error( context, "value of 40 handed to x_count", -1 );
#if !SQLITE_OMIT_UTF16
}else if( v==41 ){
Debugger.Break (); // TODO --
//const char zUtf16ErrMsg[] = { 0, 0x61, 0, 0x62, 0, 0x63, 0, 0, 0};
//sqlite3_result_error16(context, zUtf16ErrMsg[1-SQLITE_BIGENDIAN], -1);
#endif
}
}
}
static void t1CountFinalize( sqlite3_context context )
{
SumCtx p;
Mem pMem = sqlite3_aggregate_context( context, 0 );//sizeof(*p));
p = pMem._SumCtx;
if ( p != null )
{
if ( p.cnt == 42 )
{
sqlite3_result_error( context, "x_count totals to 42", -1 );
}
else
{
sqlite3_result_int( context, p != null ? (int)p.cnt : 0 );
}
}
}
 
#if !SQLITE_OMIT_DEPRECATED
static void legacyCountStep(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
/* no-op */
}
static void legacyCountFinalize( sqlite3_context context )
{
sqlite3_result_int( context, sqlite3_aggregate_count( context ) );
}
#endif
/*
** Usage: sqlite3_create_aggregate DB
**
** Call the sqlite3_create_function API on the given database in order
** to create a function named "x_count". This function is similar
** to the built-in count() function, with a few special quirks
** for testing the sqlite3_result_error() APIs.
**
** The original motivation for this routine was to be able to call the
** sqlite3_create_aggregate function while a query is in progress in order
** to test the SQLITE_MISUSE detection logic. See misuse.test.
**
** This routine was later extended to test the use of sqlite3_result_error()
** within aggregate functions.
**
** Later: It is now also extended to register the aggregate function
** "legacy_count()" with the supplied database handle. This is used
** to test the deprecated sqlite3_aggregate_count() API.
*/
static int test_create_aggregate(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = new sqlite3();
int rc;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" FILENAME\"" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_create_function( db, "x_count", 0, SQLITE_UTF8, 0, null,
t1CountStep, t1CountFinalize );
if ( rc == SQLITE_OK )
{
rc = sqlite3_create_function( db, "x_count", 1, SQLITE_UTF8, 0, null,
t1CountStep, t1CountFinalize );
}
#if !SQLITE_OMIT_DEPRECATED
if ( rc == SQLITE_OK )
{
rc = sqlite3_create_function( db, "legacy_count", 0, SQLITE_ANY, 0, null,
legacyCountStep, legacyCountFinalize
);
}
#endif
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), 0 );
return TCL.TCL_OK;
}
 
/*
** Usage: printf TEXT
**
** Send output to printf. Use this rather than puts to merge the output
** in the correct sequence with debugging printfs inserted into C code.
** Puts uses a separate buffer and debugging statements will be out of
** sequence if it is used.
*/
//static int test_printf(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// Tcl_Obj[] argv /* Text of each argument */
//){
// if( argc!=2 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " TEXT\"");
// return TCL.TCL_ERROR;
// }
// printf("%s\n", argv[1]);
// return TCL.TCL_OK;
//}
 
 
 
/*
** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
**
** Call mprintf with three integer arguments
*/
static int sqlite3_mprintf_int(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
long[] a = new long[3];
int i;
string z;
if ( argc != 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT INT INT INT\"" );
return TCL.TCL_ERROR;
}
for ( i = 2; i < 5; i++ )
{
if ( TCL.Tcl_GetLong( interp, argv[i], out a[i - 2] ) )
return TCL.TCL_ERROR;
}
z = sqlite3_mprintf( argv[1].ToString(), a[0], a[1], a[2] );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree(db,z);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER
**
** Call mprintf with three 64-bit integer arguments
*/
static int sqlite3_mprintf_int64(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
int i;
sqlite3_int64[] a = new sqlite3_int64[3];
string z;
if ( argc != 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT INT INT INT\"" );
return TCL.TCL_ERROR;
}
for ( i = 2; i < 5; i++ )
{
if ( sqlite3Atoi64( argv[i].ToString(), ref a[i - 2], argv[i].ToString().Length, SQLITE_UTF8 ) != 0 )
{
TCL.Tcl_AppendResult( interp, "argument is not a valid 64-bit integer" );
return TCL.TCL_ERROR;
}
}
z = sqlite3_mprintf( argv[1].ToString(), a[0], a[1], a[2] );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree(db,z);
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite3_mprintf_long FORMAT INTEGER INTEGER INTEGER
**
** Call mprintf with three long integer arguments. This might be the
** same as sqlite3_mprintf_int or sqlite3_mprintf_int64, depending on
** platform.
*/
static int sqlite3_mprintf_long(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
int i;
long[] a = new long[3];
long[] b = new long[3];
string z;
if ( argc != 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT INT INT INT\"" );
return TCL.TCL_ERROR;
}
for ( i = 2; i < 5; i++ )
{
if ( TCL.Tcl_GetLong( interp, argv[i], out b[i - 2] ) )
return TCL.TCL_ERROR;
a[i - 2] = b[i - 2];
//a[i-2] &= (((u64)1)<<(sizeof(int)*8))-1;
}
z = sqlite3_mprintf( argv[1].ToString(), a[0], a[1], a[2] );
TCL.Tcl_AppendResult( interp, z );
////sqlite3_free(z);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
**
** Call mprintf with two integer arguments and one string argument
*/
static int sqlite3_mprintf_str(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
long[] a = new long[3];
int i;
string z;
if ( argc < 4 || argc > 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT INT INT ?STRING?\"" );
return TCL.TCL_ERROR;
}
for ( i = 2; i < 4; i++ )
{
if ( TCL.Tcl_GetLong( interp, argv[i], out a[i - 2] ) )
return TCL.TCL_ERROR;
}
z = sqlite3_mprintf( argv[1].ToString(), a[0], a[1], argc > 4 ? argv[4].ToString() : null );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree(db,z);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING
**
** Call mprintf with two integer arguments and one string argument
*/
static int sqlite3_snprintf_str(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
long[] a = new long[3];
int i;
int n = 0;
StringBuilder z;
if ( argc < 5 || argc > 6 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" INT FORMAT INT INT ?STRING?\"" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetInt( interp, argv[1], out n ) )
return TCL.TCL_ERROR;
if ( n < 0 )
{
TCL.Tcl_AppendResult( interp, "N must be non-negative" );
return TCL.TCL_ERROR;
}
for ( i = 3; i < 5; i++ )
{
if ( TCL.Tcl_GetLong( interp, argv[i], out a[i - 3] ) )
return TCL.TCL_ERROR;
}
z = new StringBuilder( n + 1 );//sqlite3Malloc( n+1 );
sqlite3_snprintf( n, z, argv[2].ToString(), a[0], a[1], argc > 4 ? argv[5].ToString() : null );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree(db,z);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
**
** Call mprintf with two integer arguments and one double argument
*/
static int sqlite3_mprintf_double(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
long[] a = new long[3];
int i;
double r = 0;
string z;
if ( argc != 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT INT INT DOUBLE\"" );
return TCL.TCL_ERROR;
}
for ( i = 2; i < 4; i++ )
{
if ( TCL.Tcl_GetLong( interp, argv[i], out a[i - 2] ) )
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetDouble( interp, argv[4], out r ) )
return TCL.TCL_ERROR;
z = sqlite3_mprintf( argv[1].ToString(), a[0], a[1], r );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree(db,z);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE
**
** Call mprintf with a single double argument which is the product of the
** two arguments given above. This is used to generate overflow and underflow
** doubles to test that they are converted properly.
*/
static int sqlite3_mprintf_scaled(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
int i;
double[] r = new double[2];
string z;
if ( argc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT DOUBLE DOUBLE\"" );
return TCL.TCL_ERROR;
}
for ( i = 2; i < 4; i++ )
{
if ( TCL.Tcl_GetDouble( interp, argv[i], out r[i - 2] ) )
return TCL.TCL_ERROR;
}
z = sqlite3_mprintf( argv[1].ToString(), r[0] * r[1] );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree(db,z);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_stronly FORMAT STRING
**
** Call mprintf with a single double argument which is the product of the
** two arguments given above. This is used to generate overflow and underflow
** doubles to test that they are converted properly.
*/
static int sqlite3_mprintf_stronly(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
string z;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT STRING\"" );
return TCL.TCL_ERROR;
}
z = sqlite3_mprintf( argv[1].ToString(), argv[2].ToString() );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree( db, z );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_mprintf_hexdouble FORMAT HEX
**
** Call mprintf with a single double argument which is derived from the
** hexadecimal encoding of an IEEE double.
*/
static int sqlite3_mprintf_hexdouble(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
string z;
double r;
u32 x1, x2;
i64 d = 0;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" FORMAT STRING\"" );
return TCL.TCL_ERROR;
}
//if( sscanf(argv[2].ToString(), "%08x%08x", ref x2, ref x1)!=2 ){
if ( argv[2].ToString().Length != 16
|| !u32.TryParse( argv[2].ToString().Substring( 0, 8 ), System.Globalization.NumberStyles.HexNumber, null, out x2 )
|| !u32.TryParse( argv[2].ToString().Substring( 8, 8 ), System.Globalization.NumberStyles.HexNumber, null, out x1 )
)
{
TCL.Tcl_AppendResult( interp, "2nd argument should be 16-characters of hex" );
return TCL.TCL_ERROR;
}
d = x2;
d = ( d << 32 ) + x1;
#if WINDOWS_PHONE
r = BitConverter.ToDouble(BitConverter.GetBytes((long)d), 0);
#else
r = BitConverter.Int64BitsToDouble( d );// memcpy( &r, d, sizeof( r ) );
#endif
z = sqlite3_mprintf( argv[1].ToString(), r );
TCL.Tcl_AppendResult( interp, z );
//sqlite3DbFree(db,z);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_enable_shared_cache ?BOOLEAN?
**
*/
#if !SQLITE_OMIT_SHARED_CACHE
static int test_enable_shared(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
int rc;
bool enable = false;
int ret = 0;
 
if ( objc != 2 && objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "?BOOLEAN?" );
return TCL.TCL_ERROR;
}
ret = sqlite3GlobalConfig.sharedCacheEnabled ? 1 : 0;
 
if ( objc == 2 )
{
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[1], out enable ) )
{
return TCL.TCL_ERROR;
}
rc = sqlite3_enable_shared_cache( enable );
if ( rc != SQLITE_OK )
{
TCL.Tcl_SetResult( interp, sqlite3ErrStr( rc ), TCL.TCL_STATIC );
return TCL.TCL_ERROR;
}
}
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( ret ) );
return TCL.TCL_OK;
}
#endif
 
 
 
/*
** Usage: sqlite3_extended_result_codes DB BOOLEAN
**
*/
static int test_extended_result_codes(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
bool enable = false;
sqlite3 db = null;
 
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB BOOLEAN" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, objv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[2], out enable ) )
return TCL.TCL_ERROR;
sqlite3_extended_result_codes( db, enable );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_libversion_number
**
*/
static int test_libversion_number(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_libversion_number() ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_table_column_metadata DB dbname tblname colname
**
*/
#if SQLITE_ENABLE_COLUMN_METADATA
static int test_table_column_metadata(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
string zDb = null;
string zTbl = null;
string zCol = null;
int rc;
Tcl_Obj pRet;
 
string zDatatype = null;
string zCollseq = null;
int notnull = 0;
int primarykey = 0;
int autoincrement = 0;
 
if ( objc != 5 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB dbname tblname colname" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
zDb = TCL.Tcl_GetString( objv[2] );
zTbl = TCL.Tcl_GetString( objv[3] );
zCol = TCL.Tcl_GetString( objv[4] );
 
if ( zDb.Length == 0 )
zDb = null;
 
rc = sqlite3_table_column_metadata( db, zDb, zTbl, zCol,
ref zDatatype, ref zCollseq, ref notnull, ref primarykey, ref autoincrement );
 
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, sqlite3_errmsg( db ) );
return TCL.TCL_ERROR;
}
 
pRet = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement( null, pRet, TCL.Tcl_NewStringObj( zDatatype, -1 ) );
TCL.Tcl_ListObjAppendElement( null, pRet, TCL.Tcl_NewStringObj( zCollseq, -1 ) );
TCL.Tcl_ListObjAppendElement( null, pRet, TCL.Tcl_NewIntObj( notnull ) );
TCL.Tcl_ListObjAppendElement( null, pRet, TCL.Tcl_NewIntObj( primarykey ) );
TCL.Tcl_ListObjAppendElement( null, pRet, TCL.Tcl_NewIntObj( autoincrement ) );
TCL.Tcl_SetObjResult( interp, pRet );
 
return TCL.TCL_OK;
}
#endif
 
#if !SQLITE_OMIT_INCRBLOB
static int blobHandleFromObj(
Tcl_Interp interp,
Tcl_Obj *pObj,
sqlite3_blob **ppBlob
){
string z;
int n;
 
z = TCL.Tcl_GetStringFromObj(pObj, &n);
if( n==0 ){
*ppBlob = 0;
}else{
int notUsed;
TCL.Tcl_Channel channel;
ClientData instanceData;
 
channel = TCL.Tcl_GetChannel(interp, z, &notUsed);
if( null==channel ) return TCL.TCL_ERROR;
 
TCL.Tcl_Flush(channel);
TCL.Tcl_Seek(channel, 0, SEEK_SET);
 
instanceData = TCL.Tcl_GetChannelInstanceData(channel);
*ppBlob = *((sqlite3_blob *)instanceData);
}
 
return TCL.TCL_OK;
}
 
/*
** sqlite3_blob_bytes CHANNEL
*/
static int test_blob_bytes(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
){
sqlite3_blob *pBlob;
int nByte;
 
if( objc!=2 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL");
return TCL.TCL_ERROR;
}
 
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL.TCL_ERROR;
nByte = sqlite3_blob_bytes(pBlob);
TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(nByte));
 
return TCL.TCL_OK;
}
 
/*
** sqlite3_blob_close CHANNEL
*/
static int test_blob_close(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
){
sqlite3_blob *pBlob;
 
if( objc!=2 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL");
return TCL.TCL_ERROR;
}
 
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL.TCL_ERROR;
sqlite3_blob_close(pBlob);
 
return TCL.TCL_OK;
}
 
/*
** sqlite3_blob_read CHANNEL OFFSET N
**
** This command is used to test the sqlite3_blob_read() in ways that
** the Tcl channel interface does not. The first argument should
** be the name of a valid channel created by the [incrblob] method
** of a database handle. This function calls sqlite3_blob_read()
** to read N bytes from offset OFFSET from the underlying SQLite
** blob handle.
**
** On success, a byte-array object containing the read data is
** returned. On failure, the interpreter result is set to the
** text representation of the returned error code (i.e. "SQLITE_NOMEM")
** and a Tcl exception is thrown.
*/
static int test_blob_read(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
){
sqlite3_blob *pBlob;
int nByte;
int iOffset;
unsigned string zBuf = 0;
int rc;
 
if( objc!=4 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N");
return TCL.TCL_ERROR;
}
 
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL.TCL_ERROR;
if( TCL_OK!=TCL.Tcl_GetIntFromObj(interp, objv[2], &iOffset)
|| TCL_OK!=TCL.Tcl_GetIntFromObj(interp, objv[3], &nByte)
){
return TCL.TCL_ERROR;
}
 
if( nByte>0 ){
zBuf = (unsigned char )TCL.Tcl_Alloc(nByte);
}
rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset);
if( rc==SQLITE_OK ){
TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewByteArrayObj(zBuf, nByte));
}else{
TCL.Tcl_SetResult(interp, (char )sqlite3TestErrorName(rc), TCL.TCL_VOLATILE);
}
TCL.Tcl_Free((char )zBuf);
 
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
}
 
/*
** sqlite3_blob_write CHANNEL OFFSET DATA ?NDATA?
**
** This command is used to test the sqlite3_blob_write() in ways that
** the Tcl channel interface does not. The first argument should
** be the name of a valid channel created by the [incrblob] method
** of a database handle. This function calls sqlite3_blob_write()
** to write the DATA byte-array to the underlying SQLite blob handle.
** at offset OFFSET.
**
** On success, an empty string is returned. On failure, the interpreter
** result is set to the text representation of the returned error code
** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown.
*/
static int test_blob_write(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
){
sqlite3_blob *pBlob;
int iOffset;
int rc;
 
unsigned string zBuf;
int nBuf;
 
if( objc!=4 && objc!=5 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA ?NDATA?");
return TCL.TCL_ERROR;
}
 
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL.TCL_ERROR;
if( TCL_OK!=TCL.Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){
return TCL.TCL_ERROR;
}
 
zBuf = TCL.Tcl_GetByteArrayFromObj(objv[3], &nBuf);
if( objc==5 && TCL.Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){
return TCL.TCL_ERROR;
}
rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset);
if( rc!=SQLITE_OK ){
TCL.Tcl_SetResult(interp, (char )sqlite3TestErrorName(rc), TCL.TCL_VOLATILE);
}
 
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
}
 
static int test_blob_reopen(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
){
TCL.Tcl_WideInt iRowid;
sqlite3_blob *pBlob;
int rc;
 
if( objc!=3 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL ROWID");
return TCL.TCL_ERROR;
}
 
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL.TCL_ERROR;
if( TCL.Tcl_GetWideIntFromObj(interp, objv[2], &iRowid) ) return TCL.TCL_ERROR;
 
rc = sqlite3_blob_reopen(pBlob, iRowid);
if( rc!=SQLITE_OK ){
TCL.Tcl_SetResult(interp, (char )sqlite3TestErrorName(rc), TCL.TCL_VOLATILE);
}
 
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
}
#endif
 
/*
** Usage: sqlite3_create_collation_v2 DB-HANDLE NAME CMP-PROC DEL-PROC
**
** This Tcl proc is used for testing the experimental
** sqlite3_create_collation_v2() interface.
*/
public struct TestCollationX
{
public Tcl_Interp interp;
public Tcl_Obj pCmp;
public Tcl_Obj pDel;
};
//typedef struct TestCollationX TestCollationX;
static void testCreateCollationDel( ref object pCtx )
{
TestCollationX p = (TestCollationX)pCtx;
 
int rc = TCL.Tcl_EvalObjEx( p.interp, p.pDel, TCL.TCL_EVAL_DIRECT | TCL.TCL_EVAL_GLOBAL );
if ( rc != TCL.TCL_OK )
{
TCL.Tcl_BackgroundError( p.interp );
}
 
TCL.Tcl_DecrRefCount( ref p.pCmp );
TCL.Tcl_DecrRefCount( ref p.pDel );
//sqlite3Free(ref p);
}
static int testCreateCollationCmp(
object pCtx,
int nLeft,
string zLeft,
int nRight,
string zRight
)
{
TestCollationX p = (TestCollationX)pCtx;
Tcl_Obj pScript = TCL.Tcl_DuplicateObj( p.pCmp );
int iRes = 0;
 
TCL.Tcl_IncrRefCount( pScript );
TCL.Tcl_ListObjAppendElement( null, pScript, TCL.Tcl_NewStringObj( zLeft, nLeft ) );
TCL.Tcl_ListObjAppendElement( null, pScript, TCL.Tcl_NewStringObj( zRight, nRight ) );
 
if ( TCL.TCL_OK != TCL.Tcl_EvalObjEx( p.interp, pScript, TCL.TCL_EVAL_DIRECT | TCL.TCL_EVAL_GLOBAL )
|| ( TCL.Tcl_GetIntFromObj( p.interp, TCL.Tcl_GetObjResult( p.interp ), out iRes ) != TCL.TCL_OK )
)
{
TCL.Tcl_BackgroundError( p.interp );
}
TCL.Tcl_DecrRefCount( ref pScript );
 
return iRes;
}
static int test_create_collation_v2(
object clientdata, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
TestCollationX p;
sqlite3 db = null;
int rc;
 
if ( objc != 5 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB-HANDLE NAME CMP-PROC DEL-PROC" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
 
p = new TestCollationX(); //(TestCollationX )sqlite3Malloc(sizeof(TestCollationX));
p.pCmp = objv[3];
p.pDel = objv[4];
p.interp = interp;
TCL.Tcl_IncrRefCount( p.pCmp );
TCL.Tcl_IncrRefCount( p.pDel );
 
rc = sqlite3_create_collation_v2( db, TCL.Tcl_GetString( objv[2] ), 16,
p, (dxCompare)testCreateCollationCmp, testCreateCollationDel
);
if ( rc != SQLITE_MISUSE )
{
TCL.Tcl_AppendResult( interp, "sqlite3_create_collate_v2() failed to detect " +
"an invalid encoding" );
return TCL.TCL_ERROR;
}
rc = sqlite3_create_collation_v2( db, TCL.Tcl_GetString( objv[2] ), SQLITE_UTF8,
p, (dxCompare)testCreateCollationCmp, testCreateCollationDel
);
return TCL.TCL_OK;
}
 
/*
** USAGE: sqlite3_create_function_v2 DB NAME NARG ENC ?SWITCHES?
**
** Available switches are:
**
** -func SCRIPT
** -step SCRIPT
** -final SCRIPT
** -destroy SCRIPT
*/
//typedef struct CreateFunctionV2 CreateFunctionV2;
public class CreateFunctionV2
{
public Tcl_Interp interp;
public Tcl_Obj pFunc; /* Script for function invocation */
public Tcl_Obj pStep; /* Script for agg. step invocation */
public Tcl_Obj pFinal; /* Script for agg. finalization invocation */
public Tcl_Obj pDestroy; /* Destructor script */
};
static void cf2Func( sqlite3_context ctx, int nArg, sqlite3_value[] aArg )
{
}
static void cf2Step( sqlite3_context ctx, int nArg, sqlite3_value[] aArg )
{
}
static void cf2Final( sqlite3_context ctx )
{
}
static void cf2Destroy( object pUser )
{
CreateFunctionV2 p = (CreateFunctionV2)pUser;
 
if ( p.interp != null && p.pDestroy != null )
{
int rc = TCL.Tcl_EvalObjEx( p.interp, p.pDestroy, 0 );
if ( rc != TCL.TCL_OK )
TCL.Tcl_BackgroundError( p.interp );
}
 
if ( p.pFunc != null )
TCL.Tcl_DecrRefCount( ref p.pFunc );
if ( p.pStep != null )
TCL.Tcl_DecrRefCount( ref p.pStep );
if ( p.pFinal != null )
TCL.Tcl_DecrRefCount( ref p.pFinal );
if ( p.pDestroy != null )
TCL.Tcl_DecrRefCount( ref p.pDestroy );
//sqlite3_free( p);
}
 
public class EncTable
{
public string zEnc;
public int enc;
 
public EncTable( string zEnc, int enc )
{
this.zEnc = zEnc;
this.enc = enc;
}
}
 
static int test_create_function_v2(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The invoking TCL interpreter */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
string zFunc;
int nArg = 0;
int enc = 0;
CreateFunctionV2 p;
int i;
int rc;
 
EncTable[] aEnc = {
new EncTable("utf8", SQLITE_UTF8 ),
new EncTable("utf16", SQLITE_UTF16 ),
new EncTable("utf16le", SQLITE_UTF16LE ),
new EncTable("utf16be", SQLITE_UTF16BE ),
new EncTable("any", SQLITE_ANY ),
new EncTable("0", 0 )
};
 
if ( objc < 5 || ( objc % 2 ) == 0 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB NAME NARG ENC SWITCHES..." );
return TCL.TCL_ERROR;
}
 
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
zFunc = TCL.Tcl_GetString( objv[2] );
if ( TCL.Tcl_GetIntFromObj( interp, objv[3], out nArg ) != 0 )
return TCL.TCL_ERROR;
//if ( TCL.Tcl_GetIndexFromObjStruct( interp, objv[4], aEnc,//sizeof(aEnc[0]),
// "encoding", 0, ref enc)
//)
int iEnc;
for ( iEnc = 0; iEnc < aEnc.Length && ( aEnc[iEnc].zEnc != objv[4].ToString() ); iEnc++ )
{
}
if ( iEnc >= aEnc.Length )
return TCL.TCL_ERROR;
enc = aEnc[iEnc].enc;
 
p = new CreateFunctionV2();//sqlite3_malloc( sizeof( CreateFunctionV2 ) );
//Debug.Assert( p );
//memset(p, 0, sizeof(CreateFunctionV2));
p.interp = interp;
 
for ( i = 5; i < objc; i += 2 )
{
int iSwitch = 0;
string[] azSwitch = { "-func", "-step", "-final", "-destroy", "" };
if ( TCL.Tcl_GetIndexFromObj( interp, objv[i], azSwitch, "switch", 0, out iSwitch ) )
{
//sqlite3_free(p);
return TCL.TCL_ERROR;
}
 
switch ( iSwitch )
{
case 0:
p.pFunc = objv[i + 1];
break;
case 1:
p.pStep = objv[i + 1];
break;
case 2:
p.pFinal = objv[i + 1];
break;
case 3:
p.pDestroy = objv[i + 1];
break;
}
}
if ( p.pFunc != null )
p.pFunc = TCL.Tcl_DuplicateObj( p.pFunc );
if ( p.pStep != null )
p.pStep = TCL.Tcl_DuplicateObj( p.pStep );
if ( p.pFinal != null )
p.pFinal = TCL.Tcl_DuplicateObj( p.pFinal );
if ( p.pDestroy != null )
p.pDestroy = TCL.Tcl_DuplicateObj( p.pDestroy );
 
if ( p.pFunc != null )
TCL.Tcl_IncrRefCount( p.pFunc );
if ( p.pStep != null )
TCL.Tcl_IncrRefCount( p.pStep );
if ( p.pFinal != null )
TCL.Tcl_IncrRefCount( p.pFinal );
if ( p.pDestroy != null )
TCL.Tcl_IncrRefCount( p.pDestroy );
 
rc = sqlite3_create_function_v2( db, zFunc, nArg, enc, p,
( p.pFunc != null ? (dxFunc)cf2Func : (dxFunc)null ),
( p.pStep != null ? (dxStep)cf2Step : (dxStep)null ),
( p.pFinal != null ? (dxFinal)cf2Final : (dxFinal)null ),
(dxFDestroy)cf2Destroy
);
if ( rc != SQLITE_OK )
{
TCL.Tcl_ResetResult( interp );
TCL.Tcl_AppendResult( interp, sqlite3TestErrorName( rc ) );
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
*/
//static int test_load_extension(
// object clientdata, /* Not used */
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int objc, /* Number of arguments */
// Tcl_Obj[] objv /* Command arguments */
//){
// TCL.Tcl_CmdInfo cmdInfo;
// sqlite3 db=null;
// int rc;
// string zDb;
// string zFile;
// string zProc = 0;
// string zErr = 0;
 
// if( objc!=4 && objc!=3 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE FILE ?PROC?");
// return TCL.TCL_ERROR;
// }
// zDb = TCL.Tcl_GetString(objv[1]);
// zFile = TCL.Tcl_GetString(objv[2]);
// if( objc==4 ){
// zProc = TCL.Tcl_GetString(objv[3]);
// }
 
// /* Extract the C database handle from the Tcl command name */
// if( null==TCL.Tcl_GetCommandInfo(interp, zDb, cmdInfo) ){
// TCL.Tcl_AppendResult(interp, "command not found: ", zDb);
// return TCL.TCL_ERROR;
// }
// db = ((struct SqliteDb)cmdInfo.objclientdata).db;
// Debug.Assert(db);
 
// /* Call the underlying C function. If an error occurs, set rc to
// ** TCL.TCL_ERROR and load any error string into the interpreter. If no
// ** error occurs, set rc to TCL.TCL_OK.
// */
#if SQLITE_OMIT_LOAD_EXTENSION
// rc = SQLITE_ERROR;
// zErr = sqlite3_mprintf("this build omits sqlite3_load_extension()");
#else
// rc = sqlite3_load_extension(db, zFile, zProc, zErr);
#endif
// if( rc!=SQLITE_OK ){
// TCL.Tcl_SetResult(interp, zErr ? zErr : "", TCL.Tcl_VOLATILE);
// rc = TCL.TCL_ERROR;
// }else{
// rc = TCL.TCL_OK;
// }
// sqlite3DbFree(db,zErr);
 
// return rc;
//}
 
/*
** Usage: sqlite3_enable_load_extension DB-HANDLE ONOFF
*/
//static int test_enable_load(
// object clientdata, /* Not used */
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int objc, /* Number of arguments */
// Tcl_Obj[] objv /* Command arguments */
//){
// TCL.Tcl_CmdInfo cmdInfo;
// sqlite3 db=null;
// string zDb;
// int onoff;
 
// if( objc!=3 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE ONOFF");
// return TCL.TCL_ERROR;
// }
// zDb = TCL.Tcl_GetString(objv[1]);
 
// /* Extract the C database handle from the Tcl command name */
// if( null==TCL.Tcl_GetCommandInfo(interp, zDb, cmdInfo) ){
// TCL.Tcl_AppendResult(interp, "command not found: ", zDb);
// return TCL.TCL_ERROR;
// }
// db = ((struct SqliteDb)cmdInfo.objclientdata).db;
// Debug.Assert(db);
 
// /* Get the onoff parameter */
// if( TCL.Tcl_GetBooleanFromObj(interp, objv[2], out onoff) ){
// return TCL.TCL_ERROR;
// }
 
#if SQLITE_OMIT_LOAD_EXTENSION
// TCL.Tcl_AppendResult(interp, "this build omits sqlite3_load_extension()");
// return TCL.TCL_ERROR;
#else
// sqlite3_enable_load_extension(db, onoff);
// return TCL.TCL_OK;
#endif
//}
 
/*
** Usage: sqlite_abort
**
** Shutdown the process immediately. This is not a clean shutdown.
** This command is used to test the recoverability of a database in
** the event of a program crash.
*/
//static int sqlite_abort(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// Tcl_Obj[] argv /* Text of each argument */
//){
//#if defined(_MSC_VER)
// /* We do this, otherwise the test will halt with a popup message
// * that we have to click away before the test will continue.
// */
// _set_abort_behavior( 0, _CALL_REPORTFAULT );
//#endif
// exit(255);
// Debug.Assert( interp==0 ); /* This will always fail */
// return TCL.TCL_OK;
//}
 
/*
** The following routine is a user-defined SQL function whose purpose
** is to test the sqlite_set_result() API.
*/
static void testFunc( sqlite3_context context, int argc, sqlite3_value[] argv )
{
int ARGV = 0;
while ( argc >= 2 )
{
string zArg0 = sqlite3_value_text( argv[ARGV] );
if ( zArg0 != null )
{
if ( zArg0.Equals( "int", StringComparison.InvariantCultureIgnoreCase ) )
{
sqlite3_result_int( context, sqlite3_value_int( argv[ARGV + 1] ) );
}
else if ( zArg0.Equals( "int64", StringComparison.InvariantCultureIgnoreCase ) )
{
sqlite3_result_int64( context, sqlite3_value_int64( argv[ARGV + 1] ) );
}
else if ( zArg0.Equals( "string", StringComparison.InvariantCultureIgnoreCase ) )
{
sqlite3_result_text( context, sqlite3_value_text( argv[ARGV + 1] ), -1,
SQLITE_TRANSIENT );
}
else if ( zArg0.Equals( "double", StringComparison.InvariantCultureIgnoreCase ) )
{
sqlite3_result_double( context, sqlite3_value_double( argv[ARGV + 1] ) );
}
else if ( zArg0.Equals( "null", StringComparison.InvariantCultureIgnoreCase ) )
{
sqlite3_result_null( context );
}
else if ( zArg0.Equals( "value", StringComparison.InvariantCultureIgnoreCase ) )
{
sqlite3_result_value( context, argv[sqlite3_value_int( argv[ARGV + 1] )] );
}
else
{
goto error_out;
}
}
else
{
goto error_out;
}
argc -= 2;
ARGV += 2;
}
return;
 
error_out:
sqlite3_result_error( context, "first argument should be one of: " +
"int int64 string double null value", -1 );
}
 
/*
** Usage: sqlite_register_test_function DB NAME
**
** Register the test SQL function on the database DB under the name NAME.
*/
static int test_register_func(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3 db = null;
int rc;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB FUNCTION-NAME" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_create_function( db, argv[2].ToString(), -1, SQLITE_UTF8, 0,
testFunc, null, null );
if ( rc != 0 )
{
TCL.Tcl_AppendResult( interp, sqlite3ErrStr( rc ) );
return TCL.TCL_ERROR;
}
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_finalize STMT
**
** Finalize a statement handle.
*/
static int test_finalize(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int rc;
sqlite3 db = null;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " <STMT>" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
 
if ( pStmt != null )
{
db = sqlite3_db_handle( pStmt );// StmtToDb( pStmt );
}
rc = sqlite3_finalize( pStmt );
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_STATIC );//t1ErrorName( rc ), TCL.TCL_STATIC );
if ( db != null && sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_stmt_status STMT CODE RESETFLAG
**
** Get the value of a status counter from a statement.
*/
static int test_stmt_status(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int iValue;
int i, op = 0;
bool resetFlag = false;
string zOpName;
sqlite3_stmt pStmt = null;
 
//struct _aOp{
// string zName;
// int op;
//}
_aOp[] aOp = {
new _aOp( "SQLITE_STMTSTATUS_FULLSCAN_STEP", SQLITE_STMTSTATUS_FULLSCAN_STEP ),
new _aOp( "SQLITE_STMTSTATUS_SORT", SQLITE_STMTSTATUS_SORT ),
new _aOp( "SQLITE_STMTSTATUS_AUTOINDEX", SQLITE_STMTSTATUS_AUTOINDEX )
};
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT PARAMETER RESETFLAG" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
zOpName = TCL.Tcl_GetString( objv[2] );
for ( i = 0; i < ArraySize( aOp ); i++ )
{
if ( aOp[i].zName == zOpName )
{
op = aOp[i].op;
break;
}
}
if ( i >= ArraySize( aOp ) )
{
if ( TCL.Tcl_GetIntFromObj( interp, objv[2], out op ) != 0 )
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[3], out resetFlag ) )
return TCL.TCL_ERROR;
iValue = sqlite3_stmt_status( pStmt, op, resetFlag ? 1 : 0 );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( iValue ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_next_stmt DB STMT
**
** Return the next statment in sequence after STMT.
*/
static int test_next_stmt(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
sqlite3 db = null;
StringBuilder zBuf = new StringBuilder( 50 );
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " DB STMT" );
return TCL.TCL_ERROR;
}
 
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[2] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
pStmt = sqlite3_next_stmt( db, pStmt );
if ( pStmt != null )
{
if ( sqlite3TestMakePointerStr( interp, zBuf, pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_AppendResult( interp, zBuf );
}
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_stmt_readonly STMT
**
** Return true if STMT is a NULL pointer or a pointer to a statement
** that is guaranteed to leave the database unmodified.
*/
static int test_stmt_readonly(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT", 0 );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_stmt_readonly( pStmt ) ? 1 : 0;
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( rc ) );
return TCL.TCL_OK;
}
 
/*
** Usage: uses_stmt_journal STMT
**
** Return true if STMT uses a statement journal.
*/
static int uses_stmt_journal(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT", 0 );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_stmt_readonly( pStmt ) ? 1 : 0;
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( pStmt.usesStmtJournal ? 1 : 0 ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_reset STMT
**
** Reset a statement handle.
*/
static int test_reset(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " <STMT>" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
 
rc = sqlite3_reset( pStmt );
if ( pStmt != null && sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
{
return TCL.TCL_ERROR;
}
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), TCL.TCL_STATIC );
/*
if( rc !=0){
return TCL.TCL_ERROR;
}
*/
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_expired STMT
**
** Return TRUE if a recompilation of the statement is recommended.
*/
static int test_expired(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if !SQLITE_OMIT_DEPRECATED
sqlite3_stmt pStmt = null;
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " <STMT>" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 ) return TCL.TCL_ERROR;
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( sqlite3_expired( pStmt ) ) );
#endif
TCL.Tcl_SetResult( interp, "0", 0 );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3TransferBindings FROMSTMT TOSTMT
**
** Transfer all bindings from FROMSTMT over to TOSTMT
*/
static int test_transfer_bind(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if !SQLITE_OMIT_DEPRECATED
sqlite3_stmt pStmt1 = null, pStmt2 = null;
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " FROM-STMT TO-STMT" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt1 ) != 0 ) return TCL.TCL_ERROR;
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[2] ), out pStmt2 ) != 0 ) return TCL.TCL_ERROR;
TCL.Tcl_SetObjResult( interp,
TCL.Tcl_NewIntObj( pStmt1.nVar == pStmt2.nVar ? sqlite3TransferBindings( pStmt1, pStmt2 ) : TCL.TCL_ERROR ) );
#endif
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_changes DB
**
** Return the number of changes made to the database by the last SQL
** execution.
*/
static int test_changes(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_changes( db ) ) );
return TCL.TCL_OK;
}
 
/*
** This is the "static_bind_value" that variables are bound to when
** the FLAG option of sqlite3_bind is "static"
*/
//static string sqlite_static_bind_value = "";
//static int sqlite_static_bind_nbyte = 0;
 
/*
** Usage: sqlite3_bind VM IDX VALUE FLAGS
**
** Sets the value of the IDX-th occurance of "?" in the original SQL
** string. VALUE is the new value. If FLAGS=="null" then VALUE is
** ignored and the value is set to NULL. If FLAGS=="static" then
** the value is set to the value of a static variable named
** "sqlite_static_bind_value". If FLAGS=="normal" then a copy
** of the VALUE is made. If FLAGS=="blob10" then a VALUE is ignored
** an a 10-byte blob "abc\000xyz\000pq" is inserted.
*/
static int test_bind(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
sqlite3_stmt pStmt = null;
int rc;
int idx = 0;
if ( argc != 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" VM IDX VALUE (null|static|normal)\"" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, argv[1].ToString(), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetInt( interp, argv[2], out idx ) )
return TCL.TCL_ERROR;
if ( argv[4].ToString() == "null" )
{
rc = sqlite3_bind_null( pStmt, idx );
}
else if ( argv[4].ToString() == "static" )
{
rc = sqlite3_bind_text( pStmt, idx, sqlite_static_bind_value.sValue, -1, null );
}
else if ( argv[4].ToString() == "static-nbytes" )
{
rc = sqlite3_bind_text( pStmt, idx, sqlite_static_bind_value.sValue,
sqlite_static_bind_nbyte.iValue, null );
}
else if ( argv[4].ToString() == "normal" )
{
rc = sqlite3_bind_text( pStmt, idx, argv[3].ToString(), -1, SQLITE_TRANSIENT );
}
else if ( argv[4].ToString() == "blob10" )
{
rc = sqlite3_bind_text( pStmt, idx, "abc\0xyz\0pq", 10, SQLITE_STATIC );
}
else
{
TCL.Tcl_AppendResult( interp, "4th argument should be " +
"\"null\" or \"static\" or \"normal\"" );
return TCL.TCL_ERROR;
}
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != 0 )
{
StringBuilder zBuf = new StringBuilder( 50 );
sqlite3_snprintf( 50, zBuf, "(%d) ", rc );
TCL.Tcl_SetResult( interp, zBuf + sqlite3ErrStr( rc ), 0 );
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
#if !SQLITE_OMIT_UTF16
/*
** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be>
**
** This function is used to test that SQLite selects the correct collation
** sequence callback when multiple versions (for different text encodings)
** are available.
**
** Calling this routine registers the collation sequence "test_collate"
** with database handle <db>. The second argument must be a list of three
** boolean values. If the first is true, then a version of test_collate is
** registered for UTF-8, if the second is true, a version is registered for
** UTF-16le, if the third is true, a UTF-16be version is available.
** Previous versions of test_collate are deleted.
**
** The collation sequence test_collate is implemented by calling the
** following TCL script:
**
** "test_collate <enc> <lhs> <rhs>"
**
** The <lhs> and <rhs> are the two values being compared, encoded in UTF-8.
** The <enc> parameter is the encoding of the collation function that
** SQLite selected to call. The TCL test script implements the
** "test_collate" proc.
**
** Note that this will only work with one intepreter at a time, as the
** interp pointer to use when evaluating the TCL script is stored in
** pTestCollateInterp.
*/
//static Tcl_Interp * pTestCollateInterp;
//static int test_collate_func(
// object pCtx,,
// int nA, string zA,
// int nB, string zB
//){
// Tcl_Interp *i = pTestCollateInterp;
// int encin = SQLITE_PTR_TO_INT(pCtx);
// int res;
// int n;
 
// sqlite3_value pVal;
// Tcl_Obj pX;
 
// pX = TCL.Tcl_NewStringObj("test_collate", -1);
// TCL.Tcl_IncrRefCount(pX);
 
// switch( encin ){
// case SQLITE_UTF8:
// TCL.Tcl_ListObjAppendElement(i,pX,TCL.Tcl_NewStringObj("UTF-8",-1));
// break;
// case SQLITE_UTF16LE:
// TCL.Tcl_ListObjAppendElement(i,pX,TCL.Tcl_NewStringObj("UTF-16LE",-1));
// break;
// case SQLITE_UTF16BE:
// TCL.Tcl_ListObjAppendElement(i,pX,TCL.Tcl_NewStringObj("UTF-16BE",-1));
// break;
// default:
// Debug.Assert(false);
// }
 
//sqlite3BeginBenignMalloc();
// pVal = sqlite3ValueNew(0);
// if( pVal ){
// sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
// n = sqlite3_value_bytes(pVal);
// TCL.Tcl_ListObjAppendElement(i,pX,
// TCL.Tcl_NewStringObj((char)sqlite3_value_text(pVal),n));
// sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
// n = sqlite3_value_bytes(pVal);
// TCL.Tcl_ListObjAppendElement(i,pX,
// TCL.Tcl_NewStringObj((char)sqlite3_value_text(pVal),n));
// sqlite3ValueFree(pVal);
//}
//sqlite3EndBenignMalloc();
 
// TCL.Tcl_EvalObjEx(i, pX, 0);
// TCL.Tcl_DecrRefCount(pX);
// TCL.Tcl_GetIntFromObj(i, TCL.Tcl_GetObjResult(i), res);
// return res;
//}
//static int test_collate(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// sqlite3 db=null;
// int val;
// sqlite3_value pVal;
// int rc;
 
// if( objc!=5 ) goto bad_args;
// pTestCollateInterp = interp;
// if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
 
// if( TCL.TCL_OK!=TCL.Tcl_GetBooleanFromObj(interp, objv[2], out val) ) return TCL.TCL_ERROR;
// rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF8,
// (void )SQLITE_UTF8, val?test_collate_func:0);
// if( rc==SQLITE_OK ){
// string zUtf16;
// if( TCL.TCL_OK!=TCL.Tcl_GetBooleanFromObj(interp, objv[3], out val) ) return TCL.TCL_ERROR;
// rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE,
// (void )SQLITE_UTF16LE, val?test_collate_func:0);
// if( TCL.TCL_OK!=TCL.Tcl_GetBooleanFromObj(interp, objv[4], out val) ) return TCL.TCL_ERROR;
 
//#if FALSE
// if( sqlite3_iMallocFail>0 ){
// sqlite3_iMallocFail++;
// }
//#endif
// sqlite3_mutex_enter(db.mutex);
// pVal = sqlite3ValueNew(db);
// sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC);
// zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
// if( db.mallocFailed !=0{
// rc = SQLITE_NOMEM;
// }else{
// rc = sqlite3_create_collation16(db, zUtf16, SQLITE_UTF16BE,
// (void )SQLITE_UTF16BE, val?test_collate_func:0);
// }
// sqlite3ValueFree(pVal);
// sqlite3_mutex_leave(db.mutex);
// }
// if( sqlite3TestErrCode(interp, db, rc) ) return TCL.TCL_ERROR;
 
// if( rc!=SQLITE_OK ){
// TCL.Tcl_AppendResult(interp, sqlite3TestErrorName(rc));
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
 
//bad_args:
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
// TCL.Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
// return TCL.TCL_ERROR;
//}
 
/*
** When the collation needed callback is invoked, record the name of
** the requested collating function here. The recorded name is linked
** to a TCL variable and used to make sure that the requested collation
** name is correct.
*/
//static char zNeededCollation[200];
//static char pzNeededCollation = zNeededCollation;
 
 
/*
** Called when a collating sequence is needed. Registered using
** sqlite3_collation_needed16().
*/
//static void test_collate_needed_cb(
// object pCtx,,
// sqlite3 db,
// int eTextRep,
// const void pName
//){
// int enc = ENC(db);
// int i;
// string z;
// for(z = (char)pName, i=0; *z || z[1]; z++){
// if( *z ) zNeededCollation[i++] = *z;
// }
// zNeededCollation[i] = 0;
// sqlite3_create_collation(
// db, "test_collate", ENC(db), SQLITE_INT_TO_PTR(enc), test_collate_func);
//}
 
/*
** Usage: add_test_collate_needed DB
*/
//static int test_collate_needed(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// sqlite3 db=null;
// int rc;
 
// if( objc!=2 ) goto bad_args;
// if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
// rc = sqlite3_collation_needed16(db, 0, test_collate_needed_cb);
// zNeededCollation[0] = 0;
// if( sqlite3TestErrCode(interp, db, rc) ) return TCL.TCL_ERROR;
// return TCL.TCL_OK;
 
//bad_args:
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "DB");
// return TCL.TCL_ERROR;
//}
 
/*
** tclcmd: add_alignment_test_collations DB
**
** Add two new collating sequences to the database DB
**
** utf16_aligned
** utf16_unaligned
**
** Both collating sequences use the same sort order as BINARY.
** The only difference is that the utf16_aligned collating
** sequence is declared with the SQLITE_UTF16_ALIGNED flag.
** Both collating functions increment the unaligned utf16 counter
** whenever they see a string that begins on an odd byte boundary.
*/
//static int unaligned_string_counter = 0;
//static int alignmentCollFunc(
// object NotUsed,
// int nKey1, const void pKey1,
// int nKey2, const void pKey2
//){
// int rc, n;
// n = nKey1<nKey2 ? nKey1 : nKey2;
//if( nKey1>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey1))) ) unaligned_string_counter++;
//if( nKey2>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey2))) ) unaligned_string_counter++;
// rc = memcmp(pKey1, pKey2, n);
// if( rc==0 ){
// rc = nKey1 - nKey2;
// }
// return rc;
//}
//static int add_alignment_test_collations(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// sqlite3 db=null;
// if( objc>=2 ){
// if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
// sqlite3_create_collation(db, "utf16_unaligned", SQLITE_UTF16,
// 0, alignmentCollFunc);
// sqlite3_create_collation(db, "utf16_aligned", SQLITE_UTF16_ALIGNED,
// 0, alignmentCollFunc);
// }
// return SQLITE_OK;
//}
#endif // * !SQLITE_OMIT_UTF16) */
 
/*
** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be>
**
** This function is used to test that SQLite selects the correct user
** function callback when multiple versions (for different text encodings)
** are available.
**
** Calling this routine registers up to three versions of the user function
** "test_function" with database handle <db>. If the second argument is
** true, then a version of test_function is registered for UTF-8, if the
** third is true, a version is registered for UTF-16le, if the fourth is
** true, a UTF-16be version is available. Previous versions of
** test_function are deleted.
**
** The user function is implemented by calling the following TCL script:
**
** "test_function <enc> <arg>"
**
** Where <enc> is one of UTF-8, UTF-16LE or UTF16BE, and <arg> is the
** single argument passed to the SQL function. The value returned by
** the TCL script is used as the return value of the SQL function. It
** is passed to SQLite using UTF-16BE for a UTF-8 test_function(), UTF-8
** for a UTF-16LE test_function(), and UTF-16LE for an implementation that
** prefers UTF-16BE.
*/
#if !SQLITE_OMIT_UTF16
//static void test_function_utf8(
// sqlite3_context pCtx,
// int nArg,
// sqlite3_value[] argv
//){
// Tcl_Interp interp;
// Tcl_Obj pX;
// sqlite3_value pVal;
// interp = (Tcl_Interp )sqlite3_context_db_handle(pCtx);
// pX = TCL.Tcl_NewStringObj("test_function", -1);
// TCL.Tcl_IncrRefCount(pX);
// TCL.Tcl_ListObjAppendElement(interp, pX, TCL.Tcl_NewStringObj("UTF-8", -1));
// TCL.Tcl_ListObjAppendElement(interp, pX,
// TCL.Tcl_NewStringObj((char)sqlite3_value_text(argv[0]), -1));
// TCL.Tcl_EvalObjEx(interp, pX, 0);
// TCL.Tcl_DecrRefCount(pX);
// sqlite3_result_text(pCtx, TCL.Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT);
// pVal = sqlite3ValueNew(0);
// sqlite3ValueSetStr(pVal, -1, TCL.Tcl_GetStringResult(interp),
// SQLITE_UTF8, SQLITE_STATIC);
// sqlite3_result_text16be(pCtx, sqlite3_value_text16be(pVal),
// -1, SQLITE_TRANSIENT);
// sqlite3ValueFree(pVal);
//}
//static void test_function_utf16le(
// sqlite3_context pCtx,
// int nArg,
// sqlite3_value[] argv
//){
// Tcl_Interp interp;
// Tcl_Obj pX;
// sqlite3_value pVal;
// interp = (Tcl_Interp )sqlite3_context_db_handle(pCtx);
// pX = TCL.Tcl_NewStringObj("test_function", -1);
// TCL.Tcl_IncrRefCount(pX);
// TCL.Tcl_ListObjAppendElement(interp, pX, TCL.Tcl_NewStringObj("UTF-16LE", -1));
// TCL.Tcl_ListObjAppendElement(interp, pX,
// TCL.Tcl_NewStringObj((char)sqlite3_value_text(argv[0]), -1));
// TCL.Tcl_EvalObjEx(interp, pX, 0);
// TCL.Tcl_DecrRefCount(pX);
// pVal = sqlite3ValueNew(0);
// sqlite3ValueSetStr(pVal, -1, TCL.Tcl_GetStringResult(interp),
// SQLITE_UTF8, SQLITE_STATIC);
// sqlite3_result_text(pCtx,(char)sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT);
// sqlite3ValueFree(pVal);
//}
//static void test_function_utf16be(
// sqlite3_context pCtx,
// int nArg,
// sqlite3_value[] argv
//){
// Tcl_Interp interp;
// Tcl_Obj pX;
// sqlite3_value pVal;
// interp = (Tcl_Interp )sqlite3_context_db_handle(pCtx);
// pX = TCL.Tcl_NewStringObj("test_function", -1);
// TCL.Tcl_IncrRefCount(pX);
// TCL.Tcl_ListObjAppendElement(interp, pX, TCL.Tcl_NewStringObj("UTF-16BE", -1));
// TCL.Tcl_ListObjAppendElement(interp, pX,
// TCL.Tcl_NewStringObj((char)sqlite3_value_text(argv[0]), -1));
// TCL.Tcl_EvalObjEx(interp, pX, 0);
// TCL.Tcl_DecrRefCount(pX);
// pVal = sqlite3ValueNew(0);
// sqlite3ValueSetStr(pVal, -1, TCL.Tcl_GetStringResult(interp),
// SQLITE_UTF8, SQLITE_STATIC);
// sqlite3_result_text16(pCtx, sqlite3_value_text16le(pVal),
// -1, SQLITE_TRANSIENT);
// sqlite3_result_text16be(pCtx, sqlite3_value_text16le(pVal),
// -1, SQLITE_TRANSIENT);
// sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal),
// -1, SQLITE_TRANSIENT);
// sqlite3ValueFree(pVal);
//}
#endif // * SQLITE_OMIT_UTF16 */
//static int test_function(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
#if !SQLITE_OMIT_UTF16
// sqlite3 db=null;
// int val;
 
// if( objc!=5 ) goto bad_args;
// if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
 
// if( TCL.TCL_OK!=TCL.Tcl_GetBooleanFromObj(interp, objv[2], out val) ) return TCL.TCL_ERROR;
// if( val ){
// sqlite3_create_function(db, "test_function", 1, SQLITE_UTF8,
// interp, test_function_utf8, 0, 0);
// }
// if( TCL.TCL_OK!=TCL.Tcl_GetBooleanFromObj(interp, objv[3], out val) ) return TCL.TCL_ERROR;
// if( val ){
// sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16LE,
// interp, test_function_utf16le, 0, 0);
// }
// if( TCL.TCL_OK!=TCL.Tcl_GetBooleanFromObj(interp, objv[4], out val) ) return TCL.TCL_ERROR;
// if( val ){
// sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16BE,
// interp, test_function_utf16be, 0, 0);
// }
 
// return TCL.TCL_OK;
//bad_args:
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
// TCL.Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
#endif // * SQLITE_OMIT_UTF16 */
// return TCL.TCL_ERROR;
//}
 
/*
** Usage: test_errstr <err code>
**
** Test that the english language string equivalents for sqlite error codes
** are sane. The parameter is an integer representing an sqlite error code.
** The result is a list of two elements, the string representation of the
** error code and the english language explanation.
*/
static int test_errstr(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
string zCode;
int i;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "<error code>" );
}
 
zCode = TCL.Tcl_GetString( objv[1] );
for ( i = 0; i < 200; i++ )
{
if ( t1ErrorName( i ).Equals( zCode ) )
break;
}
TCL.Tcl_SetResult( interp, sqlite3ErrStr( i ), 0 );
return TCL.TCL_OK;
}
 
/*
** Usage: breakpoint
**
** This routine exists for one purpose - to provide a place to put a
** breakpoint with GDB that can be triggered using TCL code. The use
** for this is when a particular test fails on (say) the 1485th iteration.
** In the TCL test script, we can add code like this:
**
** if {$i==1485} breakpoint
**
** Then run testfixture in the debugger and wait for the breakpoint to
** fire. Then additional breakpoints can be set to trace down the bug.
*/
static int test_breakpoint(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
Tcl_Obj[] argv /* Text of each argument */
)
{
return TCL.TCL_OK; /* Do nothing */
}
 
/*
** Usage: sqlite3_bind_zeroblob STMT IDX N
**
** Test the sqlite3_bind_zeroblob interface. STMT is a prepared statement.
** IDX is the index of a wildcard in the prepared statement. This command
** binds a N-byte zero-filled BLOB to the wildcard.
*/
static int test_bind_zeroblob(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int idx = 0;
int n = 0;
int rc;
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT IDX N" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out idx ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out n ) )
return TCL.TCL_ERROR;
 
rc = sqlite3_bind_zeroblob( pStmt, idx, n );
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
return TCL.TCL_ERROR;
}
 
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_int STMT N VALUE
**
** Test the sqlite3_bind_int interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
** binds a 32-bit integer VALUE to that wildcard.
*/
static int test_bind_int(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int idx = 0;
int value = 0;
int rc;
 
if ( objc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT N VALUE" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out idx ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out value ) )
return TCL.TCL_ERROR;
 
rc = sqlite3_bind_int( pStmt, idx, value );
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
return TCL.TCL_ERROR;
}
 
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite3_bind_int64 STMT N VALUE
**
** Test the sqlite3_bind_int64 interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
** binds a 64-bit integer VALUE to that wildcard.
*/
static int test_bind_int64(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int idx = 0;
i64 value = 0;
int rc;
 
if ( objc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT N VALUE" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out idx ) )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetWideIntFromObj( interp, objv[3], out value ) )
return TCL.TCL_ERROR;
 
rc = sqlite3_bind_int64( pStmt, idx, value );
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
return TCL.TCL_ERROR;
}
 
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite3_bind_double STMT N VALUE
**
** Test the sqlite3_bind_double interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
** binds a 64-bit integer VALUE to that wildcard.
*/
class _aSpecialFp
{
public string zName; /* Name of the special floating point value */
public u32 iUpper; /* Upper 32 bits */
public u32 iLower; /* Lower 32 bits */
public _aSpecialFp( string zName, u32 iUpper, u32 iLower )
{
this.zName = zName;
this.iUpper = iUpper;
this.iLower = iLower;
}
}
 
static int test_bind_double(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
;
int idx = 0;
double value = 0;
int rc;
string zVal;
int i;
_aSpecialFp[] aSpecialFp = new _aSpecialFp[] {
new _aSpecialFp( "NaN", 0x7fffffff, 0xffffffff ),
new _aSpecialFp( "SNaN", 0x7ff7ffff, 0xffffffff ),
new _aSpecialFp( "-NaN", 0xffffffff, 0xffffffff ),
new _aSpecialFp( "-SNaN", 0xfff7ffff, 0xffffffff ),
new _aSpecialFp( "+Inf", 0x7ff00000, 0x00000000 ),
new _aSpecialFp( "-Inf", 0xfff00000, 0x00000000 ),
new _aSpecialFp( "Epsilon", 0x00000000, 0x00000001 ),
new _aSpecialFp( "-Epsilon", 0x80000000, 0x00000001 ),
new _aSpecialFp( "NaN0", 0x7ff80000, 0x00000000 ),
new _aSpecialFp( "-NaN0", 0xfff80000, 0x00000000 ),
};
 
if ( objc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT N VALUE" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out idx ) )
return TCL.TCL_ERROR;
 
/* Intercept the string "NaN" and generate a NaN value for it.
** All other strings are passed through to TCL.Tcl_GetDoubleFromObj().
** TCL.Tcl_GetDoubleFromObj() should understand "NaN" but some versions
** contain a bug.
*/
zVal = TCL.Tcl_GetString( objv[3] );
for ( i = 0; i < aSpecialFp.Length; i++ )
{//sizeof(aSpecialFp)/sizeof(aSpecialFp[0]); i++){
if ( aSpecialFp[i].zName == zVal )
{
i64 x;
x = aSpecialFp[i].iUpper;
x <<= 32;
x |= aSpecialFp[i].iLower;
Debug.Assert( sizeof( double ) == 8 );
Debug.Assert( sizeof( sqlite3_u3264 ) == 8 );
#if WINDOWS_PHONE
value = BitConverter.ToDouble(BitConverter.GetBytes((long)x), 0);
#else
value = BitConverter.Int64BitsToDouble( x );//memcpy(&value, x, 8);
#endif
//value = Double.NaN;
break;
}
}
if ( ( i >= aSpecialFp.Length ) && //sizeof(aSpecialFp)/sizeof(aSpecialFp[0]) &&
TCL.Tcl_GetDoubleFromObj( interp, objv[3], out value ) )
{
return TCL.TCL_ERROR;
}
rc = sqlite3_bind_double( pStmt, idx, value );
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
return TCL.TCL_ERROR;
}
 
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_null STMT N
**
** Test the sqlite3_bind_null interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
** binds a NULL to the wildcard.
*/
static int test_bind_null(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
;
int idx = 0;
int rc;
 
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT N" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out idx ) )
return TCL.TCL_ERROR;
 
rc = sqlite3_bind_null( pStmt, idx );
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
return TCL.TCL_ERROR;
}
 
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_text STMT N STRING BYTES
**
** Test the sqlite3_bind_text interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
** binds a UTF-8 string STRING to the wildcard. The string is BYTES bytes
** long.
*/
static int test_bind_text(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int idx = 0;
int bytes = 0;
byte[] value;
int rc;
 
if ( objc != 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT N VALUE BYTES" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out idx ) )
return TCL.TCL_ERROR;
value = TCL.Tcl_GetByteArrayFromObj( objv[3], out bytes );
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[4], out bytes ) )
return TCL.TCL_ERROR;
 
rc = sqlite3_bind_text( pStmt, idx, Encoding.UTF8.GetString( value, 0, value.Length ), bytes, SQLITE_TRANSIENT );
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, sqlite3TestErrorName( rc ) );
return TCL.TCL_ERROR;
}
 
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_text16 ?-static? STMT N STRING BYTES
**
** Test the sqlite3_bind_text16 interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
** binds a UTF-16 string STRING to the wildcard. The string is BYTES bytes
** long.
*/
static int test_bind_text16(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if !SQLITE_OMIT_UTF16
sqlite3_stmt pStmt=null;
int idx=0;
int bytes=0;
string value;
int rc;
 
dxDel xDel = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
Tcl_Obj oStmt = objv[objc-4];
Tcl_Obj oN = objv[objc-3];
Tcl_Obj oString = objv[objc-2];
Tcl_Obj oBytes = objv[objc-1];
 
if( objc!=5 && objc!=6){
TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
return TCL.TCL_ERROR;
}
 
if( getStmtPointer(interp, TCL.Tcl_GetString(oStmt), out pStmt)!=0 ) return TCL.TCL_ERROR;
if( TCL.Tcl_GetIntFromObj(interp, oN, out idx) ) return TCL.TCL_ERROR;
int dummy0 = 0;
value = Encoding.UTF8.GetString(TCL.Tcl_GetByteArrayFromObj( oString, out dummy0 ));
if( TCL.Tcl_GetIntFromObj(interp, oBytes, out bytes) ) return TCL.TCL_ERROR;
 
rc = sqlite3_bind_text16(pStmt, idx, value, bytes, xDel);
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) !=0) return TCL.TCL_ERROR;
if( rc!=SQLITE_OK ){
TCL.Tcl_AppendResult(interp, sqlite3TestErrorName(rc));
return TCL.TCL_ERROR;
}
 
#endif // * SQLITE_OMIT_UTF16 */
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_blob ?-static? STMT N DATA BYTES
**
** Test the sqlite3_bind_blob interface. STMT is a prepared statement.
** N is the index of a wildcard in the prepared statement. This command
** binds a BLOB to the wildcard. The BLOB is BYTES bytes in size.
*/
static int test_bind_blob(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int idx = 0;
int bytes = 0;
byte[] value;
int rc;
dxDel xDestructor = SQLITE_TRANSIENT;
 
int iObjv = 0;
if ( objc != 5 && objc != 6 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " STMT N DATA BYTES" );
return TCL.TCL_ERROR;
}
 
if ( objc == 6 )
{
xDestructor = SQLITE_STATIC;
iObjv++;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[iObjv + 1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[iObjv + 2], out idx ) )
return TCL.TCL_ERROR;
value = Encoding.UTF8.GetBytes( TCL.Tcl_GetString( objv[iObjv + 3] ) );
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[iObjv + 4], out bytes ) )
return TCL.TCL_ERROR;
 
rc = sqlite3_bind_blob( pStmt, idx, value, bytes, xDestructor );
if ( sqlite3TestErrCode( interp, StmtToDb( pStmt ), rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
return TCL.TCL_ERROR;
}
 
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_parameter_count STMT
**
** Return the number of wildcards in the given statement.
*/
static int test_bind_parameter_count(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_bind_parameter_count( pStmt ) ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_parameter_name STMT N
**
** Return the name of the Nth wildcard. The first wildcard is 1.
** An empty string is returned if N is out of range or if the wildcard
** is nameless.
*/
static int test_bind_parameter_name(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int i = 0;
 
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT N" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out i ) )
return TCL.TCL_ERROR;
TCL.Tcl_SetObjResult( interp,
TCL.Tcl_NewStringObj( sqlite3_bind_parameter_name( pStmt, i ), -1 )
);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_bind_parameter_index STMT NAME
**
** Return the index of the wildcard called NAME. Return 0 if there is
** no such wildcard.
*/
static int test_bind_parameter_index(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
 
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT NAME" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_SetObjResult( interp,
TCL.Tcl_NewIntObj(
sqlite3_bind_parameter_index( pStmt, TCL.Tcl_GetString( objv[2] ) )
)
);
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_clear_bindings STMT
**
*/
static int test_clear_bindings(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_clear_bindings( pStmt ) ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_sleep MILLISECONDS
*/
static int test_sleep(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int ms = 0;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "MILLISECONDS" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out ms ) )
{
return TCL.TCL_ERROR;
}
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_sleep( ms ) ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_extended_errcode DB
**
** Return the string representation of the most recent sqlite3_* API
** error code. e.g. "SQLITE_ERROR".
*/
static int test_ex_errcode(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_extended_errcode( db );
TCL.Tcl_AppendResult( interp, t1ErrorName( rc ) );
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite3_errcode DB
**
** Return the string representation of the most recent sqlite3_* API
** error code. e.g. "SQLITE_ERROR".
*/
static int test_errcode(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
int rc;
StringBuilder zBuf = new StringBuilder( 50 );
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_errcode( db );
if ( ( rc & 0xff ) == rc )
{
zBuf.Length = 0;
}
else
{
sqlite3_snprintf( 30, zBuf, "+%d", rc >> 8 );
}
TCL.Tcl_AppendResult( interp, t1ErrorName( rc ), zBuf );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_errmsg DB
**
** Returns the UTF-8 representation of the error message string for the
** most recent sqlite3_* API call.
*/
static int test_errmsg(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
string zErr;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
 
zErr = sqlite3_errmsg( db );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewStringObj( zErr, -1 ) );
return TCL.TCL_OK;
}
 
/*
** Usage: test_errmsg16 DB
**
** Returns the UTF-16 representation of the error message string for the
** most recent sqlite3_* API call. This is a byte array object at the TCL
** level, and it includes the 0x00 0x00 terminator bytes at the end of the
** UTF-16 string.
*/
//static int test_errmsg16(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
#if !SQLITE_OMIT_UTF16
sqlite3 db;
string zErr;
string z;
int bytes = 0;
 
if( objc!=2 ){
TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
TCL.Tcl_GetString(objv[0]), " DB", 0);
return TCL.TCL_ERROR;
}
if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), &db) ) return TCL.TCL_ERROR;
 
zErr = sqlite3_errmsg16(db);
if( zErr ){
z = zErr;
for(bytes=0; z[bytes] || z[bytes+1]; bytes+=2){}
}
TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewByteArrayObj(zErr, bytes));
#endif // * SQLITE_OMIT_UTF16 */
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_prepare DB sql bytes ?tailvar?
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
** variable that is set to the unused portion of <sql> (if any). A
** STMT handle is returned.
*/
static int test_prepare(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
string zSql;
int bytes = 0;
string zTail = "";
sqlite3_stmt pStmt = null;
StringBuilder zBuf = new StringBuilder( 50 );
int rc;
 
if ( objc != 5 && objc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " DB sql bytes ?tailvar?" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
zSql = TCL.Tcl_GetString( objv[2] );
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out bytes ) )
return TCL.TCL_ERROR;
 
if ( bytes > zSql.Length )
bytes = zSql.Length;
rc = sqlite3_prepare( db, zSql, bytes, ref pStmt, ref zTail );
TCL.Tcl_ResetResult( interp );
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
if ( zTail != null && objc >= 5 )
{
if ( bytes >= 0 )
{
bytes = bytes - zSql.Length - zTail.Length;// ( zTail - zSql );
}
if ( zTail.Length < bytes )
{
bytes = zTail.Length;
}
TCL.Tcl_ObjSetVar2( interp, objv[4], null, TCL.Tcl_NewStringObj( zTail, bytes ), 0 );
}
if ( rc != SQLITE_OK )
{
Debug.Assert( pStmt == null );
sqlite3_snprintf( 200, zBuf, "(%d) ", rc );
TCL.Tcl_SetResult( interp, zBuf + sqlite3_errmsg( db ), 0 );
return TCL.TCL_ERROR;
}
 
if ( pStmt != null )
{
if ( sqlite3TestMakePointerStr( interp, zBuf, pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_AppendResult( interp, zBuf, null );
}
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_prepare_v2 DB sql bytes ?tailvar?
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
** variable that is set to the unused portion of <sql> (if any). A
** STMT handle is returned.
*/
static int test_prepare_v2(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
string zSql;
int bytes = 0;
string zTail = "";
sqlite3_stmt pStmt = null;
StringBuilder zBuf = new StringBuilder( 50 );
int rc;
 
if ( objc != 5 && objc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " DB sql bytes ?tailvar?", null );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
zSql = TCL.Tcl_GetString( objv[2] );
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out bytes ) )
return TCL.TCL_ERROR;
 
rc = sqlite3_prepare_v2( db, zSql, bytes, ref pStmt, ref zTail );
Debug.Assert( rc == SQLITE_OK || pStmt == null );
TCL.Tcl_ResetResult( interp );
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
if ( zTail != null && objc >= 5 )
{
if ( bytes >= 0 )
{
bytes = bytes - zSql.Length - zTail.Length;// ( zTail - zSql );
}
TCL.Tcl_ObjSetVar2( interp, objv[4], null, TCL.Tcl_NewStringObj( zTail, bytes ), 0 );
}
if ( rc != SQLITE_OK )
{
Debug.Assert( pStmt == null );
sqlite3_snprintf( 50, zBuf, "(%d) ", rc );
TCL.Tcl_AppendResult( interp, zBuf, sqlite3_errmsg( db ) );
return TCL.TCL_ERROR;
}
 
if ( pStmt != null )
{
if ( sqlite3TestMakePointerStr( interp, zBuf, pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_AppendResult( interp, zBuf );
}
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_prepare_tkt3134 DB
**
** Generate a prepared statement for a zero-byte string as a test
** for ticket #3134. The string should be preceeded by a zero byte.
*/
static int test_prepare_tkt3134(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
string zSql = "\000SELECT 1";
sqlite3_stmt pStmt = null;
StringBuilder zBuf = new StringBuilder( 50 );
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " DB sql bytes tailvar" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_prepare_v2( db, zSql.Substring( 1 ), 0, ref pStmt, 0 );
Debug.Assert( rc == SQLITE_OK || pStmt == null );
if ( sqlite3TestErrCode( interp, db, rc ) != 0 )
return TCL.TCL_ERROR;
if ( rc != SQLITE_OK )
{
Debug.Assert( pStmt == null );
zBuf.Length = 0;
zBuf.Append( rc.ToString() ); //sprintf( zBuf, "(%d) ", rc );
TCL.Tcl_AppendResult( interp, zBuf, sqlite3_errmsg( db ) );
return TCL.TCL_ERROR;
}
 
if ( pStmt != null )
{
if ( sqlite3TestMakePointerStr( interp, zBuf, pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_AppendResult( interp, zBuf );
}
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_prepare16 DB sql bytes tailvar
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
** variable that is set to the unused portion of <sql> (if any). A
** STMT handle is returned.
*/
static int test_prepare16(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if !SQLITE_OMIT_UTF16
sqlite3 db=null;
string zSql;
string zTail = 0;
Tcl_Obj pTail = 0;
sqlite3_stmt pStmt = null;
char zBuf[50];
int rc;
int bytes; /* The integer specified as arg 3 */
int objlen; /* The byte-array length of arg 2 */
 
if( objc!=5 && objc!=4 ){
TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
TCL.Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
return TCL.TCL_ERROR;
}
if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
zSql = TCL.Tcl_GetByteArrayFromObj(objv[2], out objlen);
if( TCL.Tcl_GetIntFromObj(interp, objv[3], out bytes) ) return TCL.TCL_ERROR;
 
rc = sqlite3_prepare16(db, zSql, bytes, pStmt, objc>=5 ? &zTail : 0);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL.TCL_ERROR;
if( rc !=0){
return TCL.TCL_ERROR;
}
 
if( objc>=5 ){
if( zTail ){
objlen = objlen - ((u8 )zTail-(u8 )zSql);
}else{
objlen = 0;
}
pTail = TCL.Tcl_NewByteArrayObj((u8 )zTail, objlen);
TCL.Tcl_IncrRefCount(pTail);
Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
TCL.Tcl_DecrRefCount(pTail);
}
 
if( pStmt ){
if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL.TCL_ERROR;
}
TCL.Tcl_AppendResult(interp, zBuf);
#endif // * SQLITE_OMIT_UTF16 */
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_prepare16_v2 DB sql bytes tailvar
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
** variable that is set to the unused portion of <sql> (if any). A
** STMT handle is returned.
*/
//static int test_prepare16_v2(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
#if !SQLITE_OMIT_UTF16
// sqlite3 db=null;
// string zSql;
// string zTail = 0;
// Tcl_Obj pTail = 0;
// sqlite3_stmt pStmt = null;
// char zBuf[50];
// int rc;
// int bytes; /* The integer specified as arg 3 */
// int objlen; /* The byte-array length of arg 2 */
 
// if( objc!=5 && objc!=4 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
// TCL.Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
// return TCL.TCL_ERROR;
// }
// if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
// zSql = TCL.Tcl_GetByteArrayFromObj(objv[2], out objlen);
// if( TCL.Tcl_GetIntFromObj(interp, objv[3], out bytes) ) return TCL.TCL_ERROR;
 
// rc = sqlite3_prepare16_v2(db, zSql, bytes, pStmt,objc>=5 ? &zTail : 0);
// if( sqlite3TestErrCode(interp, db, rc) ) return TCL.TCL_ERROR;
// if( rc !=0){
// return TCL.TCL_ERROR;
// }
 
if( objc>=5 ){
if( zTail ){
objlen = objlen - ((u8 )zTail-(u8 )zSql);
}else{
objlen = 0;
}
pTail = TCL.Tcl_NewByteArrayObj((u8 )zTail, objlen);
TCL.Tcl_IncrRefCount(pTail);
Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
TCL.Tcl_DecrRefCount(pTail);
// }
 
// if( pStmt ){
// if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL.TCL_ERROR;
// }
// TCL.Tcl_AppendResult(interp, zBuf);
#endif // * SQLITE_OMIT_UTF16 */
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_open filename ?options-list?
*/
static int test_open(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
string zFilename;
SqliteDb db = new SqliteDb();
int rc;
StringBuilder zBuf = new StringBuilder( 100 );
if ( objc != 3 && objc != 2 && objc != 1 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " filename options-list" );
return TCL.TCL_ERROR;
}
 
zFilename = objc > 1 ? TCL.Tcl_GetString( objv[1] ) : null;
rc = sqlite3_open( zFilename, out db.db );
 
if ( sqlite3TestMakePointerStr( interp, zBuf, db ) != TCL.TCL_OK )
return TCL.TCL_ERROR;
TCL.Tcl_AppendResult( interp, zBuf );
return TCL.TCL_OK;
}
 
class OpenFlag
{
public string zFlag;
public int flag;
 
public OpenFlag( string zFlag, int flag )
{
this.zFlag = zFlag;
this.flag = flag;
}
}
/*
** Usage: sqlite3_open_v2 FILENAME FLAGS VFS
*/
static int test_open_v2(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
string zFilename;
string zVfs;
int flags = 0;
sqlite3 db = null;
int rc;
StringBuilder zBuf = new StringBuilder( 100 );
 
int nFlag = 0;
Tcl_Obj[] apFlag = null;
int i;
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "FILENAME FLAGS VFS" );
return TCL.TCL_ERROR;
}
zFilename = TCL.Tcl_GetString( objv[1] );
zVfs = TCL.Tcl_GetString( objv[3] );
if ( zVfs[0] == 0x00 )
zVfs = null;
 
rc = TCL.Tcl_ListObjGetElements( interp, objv[2], out nFlag, out apFlag ) ? TCL.TCL_OK : 1;
if ( rc != TCL.TCL_OK )
return rc;
for ( i = 0; i < nFlag; i++ )
{
int iFlag;
OpenFlag[] aFlag = new OpenFlag[] {
new OpenFlag( "SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY ),
new OpenFlag( "SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE ),
new OpenFlag( "SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE ),
new OpenFlag( "SQLITE_OPEN_DELETEONCLOSE", SQLITE_OPEN_DELETEONCLOSE ),
new OpenFlag( "SQLITE_OPEN_EXCLUSIVE", SQLITE_OPEN_EXCLUSIVE ),
new OpenFlag( "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY ),
new OpenFlag( "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB ),
new OpenFlag( "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB ),
new OpenFlag( "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB ),
new OpenFlag( "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL ),
new OpenFlag( "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL ),
new OpenFlag( "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL ),
new OpenFlag( "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL ),
new OpenFlag( "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX ),
new OpenFlag( "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX ),
new OpenFlag( "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE ),
new OpenFlag( "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE ),
new OpenFlag( "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL ),
new OpenFlag( "SQLITE_OPEN_URI", SQLITE_OPEN_URI ),
new OpenFlag( null, 0 )
};
//rc = TCL.Tcl_GetIndexFromObjStruct( interp, apFlag[i], aFlag, sizeof( aFlag[0] ),
// "flag", 0, ref iFlag );
 
for ( iFlag = 0; iFlag < aFlag.Length && ( aFlag[iFlag].zFlag != objv[4].ToString() ); iFlag++ )
{
}
if ( iFlag >= aFlag.Length )
return TCL.TCL_ERROR;
flags |= aFlag[iFlag].flag;
}
 
rc = sqlite3_open_v2( zFilename, out db, flags, zVfs );
if ( sqlite3TestMakePointerStr( interp, zBuf, db ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_AppendResult( interp, zBuf, 0 );
return TCL.TCL_OK;
}
/*
** Usage: sqlite3_open16 filename options
*/
//static int test_open16(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
#if !SQLITE_OMIT_UTF16
// string zFilename;
// sqlite3 db=null;
// int rc;
// char zBuf[100];
 
// if( objc!=3 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
// TCL.Tcl_GetString(objv[0]), " filename options-list", 0);
// return TCL.TCL_ERROR;
// }
 
// zFilename = TCL.Tcl_GetByteArrayFromObj(objv[1], 0);
// rc = sqlite3_open16(zFilename, ref db);
 
// if ( sqlite3TestMakePointerStr( interp, zBuf, db ) != TCL.TCL_OK ) return TCL.TCL_ERROR;
// TCL.Tcl_AppendResult(interp, zBuf);
#endif // * SQLITE_OMIT_UTF16 */
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_complete16 <UTF-16 string>
**
** Return 1 if the supplied argument is a complete SQL statement, or zero
** otherwise.
*/
//static int test_complete16(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
#if !SQLITE_OMIT_COMPLETE && !SQLITE_OMIT_UTF16
// string zBuf;
 
// if( objc!=2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "<utf-16 sql>");
// return TCL.TCL_ERROR;
// }
 
// zBuf = (char)TCL.Tcl_GetByteArrayFromObj(objv[1], 0);
// TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(sqlite3_complete16(zBuf)));
#endif // * SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_step STMT
**
** Advance the statement to the next row.
*/
static int test_step(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_step( pStmt );
 
/* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL.TCL_ERROR; */
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), 0 );
return TCL.TCL_OK;
}
 
static int test_sql(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
TCL.Tcl_SetResult( interp, sqlite3_sql( pStmt ), TCL.TCL_VOLATILE );
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite3_column_count STMT
**
** Return the number of columns returned by the sql statement STMT.
*/
static int test_column_count(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
 
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_column_count( pStmt ) ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_column_type STMT column
**
** Return the type of the data in column 'column' of the current row.
*/
static int test_column_type(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int col = 0;
int tp;
 
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out col ) )
return TCL.TCL_ERROR;
 
tp = sqlite3_column_type( pStmt, col );
switch ( tp )
{
case SQLITE_INTEGER:
TCL.Tcl_SetResult( interp, "INTEGER", TCL.TCL_STATIC );
break;
case SQLITE_NULL:
TCL.Tcl_SetResult( interp, "NULL", TCL.TCL_STATIC );
break;
case SQLITE_FLOAT:
TCL.Tcl_SetResult( interp, "FLOAT", TCL.TCL_STATIC );
break;
case SQLITE_TEXT:
TCL.Tcl_SetResult( interp, "TEXT", TCL.TCL_STATIC );
break;
case SQLITE_BLOB:
TCL.Tcl_SetResult( interp, "BLOB", TCL.TCL_STATIC );
break;
default:
Debugger.Break();
break;
}
 
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_column_int64 STMT column
**
** Return the data in column 'column' of the current row cast as an
** wide (64-bit) integer.
*/
static int test_column_int64(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = new sqlite3_stmt();
int col = 0;
i64 iVal;
 
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != TCL.TCL_OK )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out col ) )
return TCL.TCL_ERROR;
 
iVal = sqlite3_column_int64( pStmt, col );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewWideIntObj( iVal ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_column_blob STMT column
*/
static int test_column_blob(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = new sqlite3_stmt();
int col = 0;
 
int len;
byte[] pBlob;
 
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != TCL.TCL_OK )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out col ) )
return TCL.TCL_ERROR;
 
len = sqlite3_column_bytes( pStmt, col );
pBlob = sqlite3_column_blob( pStmt, col );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewByteArrayObj( pBlob, len ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_column_double STMT column
**
** Return the data in column 'column' of the current row cast as a double.
*/
static int test_column_double(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = new sqlite3_stmt();
int col = 0;
double rVal;
 
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != TCL.TCL_OK )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out col ) )
return TCL.TCL_ERROR;
 
rVal = sqlite3_column_double( pStmt, col );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewDoubleObj( rVal ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_data_count STMT
**
** Return the number of columns returned by the sql statement STMT.
*/
static int test_data_count(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != TCL.TCL_OK )
return TCL.TCL_ERROR;
 
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_data_count( pStmt ) ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_column_text STMT column
**
** Usage: sqlite3_column_decltype STMT column
**
** Usage: sqlite3_column_name STMT column
*/
static int test_stmt_utf8(
object clientdata, /* Pointer to SQLite API function to be invoke */
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int col = 0;
dxColumn xFunc;//string (*xFunc)(sqlite3_stmt*, int);
string zRet;
 
xFunc = (dxColumn)clientdata; //(string ()(sqlite3_stmt*, int))clientData;
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out col ) )
return TCL.TCL_ERROR;
zRet = (string)xFunc( pStmt, col );
if ( zRet != null )
{
TCL.Tcl_SetResult( interp, zRet, 0 );
}
return TCL.TCL_OK;
}
 
static int test_global_recover(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if !SQLITE_OMIT_DEPRECATED
int rc;
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
rc = sqlite3_global_recover();
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), TCL.TCL_STATIC );
#else
TCL.Tcl_SetResult( interp, t1ErrorName( SQLITE_OK ), TCL.TCL_STATIC );
#endif
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_column_text STMT column
**
** Usage: sqlite3_column_decltype STMT column
**
** Usage: sqlite3_column_name STMT column
*/
//static int test_stmt_utf16(
// object clientdata, /* Pointer to SQLite API function to be invoked */
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
#if !SQLITE_OMIT_UTF16
// sqlite3_stmt pStmt;
// int col;
// Tcl_Obj pRet;
// string zName16;
// const void *(*xFunc)(sqlite3_stmt*, int);
 
xFunc = (dxColumn)clientdata; //(string ()(sqlite3_stmt*, int))clientData;
// if( objc!=3 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
// TCL.Tcl_GetString(objv[0]), " STMT column", 0);
// return TCL.TCL_ERROR;
// }
 
// if( getStmtPointer(interp, TCL.Tcl_GetString(objv[1]), pStmt) ) return TCL.TCL_ERROR;
// if( TCL.Tcl_GetIntFromObj(interp, objv[2], out col) ) return TCL.TCL_ERROR;
 
// zName16 = xFunc(pStmt, col);
// if( zName16 ){
int n;
string z = zName16;
for(n=0; z[n] || z[n+1]; n+=2){}
pRet = TCL.Tcl_NewByteArrayObj(zName16, n+2);
// TCL.Tcl_SetObjResult(interp, pRet);
// }
#endif // * SQLITE_OMIT_UTF16 */
 
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_column_int STMT column
**
** Usage: sqlite3_column_bytes STMT column
**
** Usage: sqlite3_column_bytes16 STMT column
**
*/
static int test_stmt_int(
object clientdata, /* Pointer to SQLite API function to be invoked */
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_stmt pStmt = null;
int col = 0;
dxColumn_I xFunc;//(sqlite3_stmt*, int) ;
 
xFunc = (dxColumn_I)clientdata; //(int ()(sqlite3_stmt*, int))clientData;
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetString( objv[0] ), " STMT column" );
return TCL.TCL_ERROR;
}
 
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out col ) )
return TCL.TCL_ERROR;
 
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( xFunc( pStmt, col ) ) );
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite_set_magic DB MAGIC-NUMBER
**
** Set the db.magic value. This is used to test error recovery logic.
*/
static int sqlite_set_magic(
object clientdata, /* Pointer to SQLite API function to be invoked */
Tcl_Interp interp,
int argc,
Tcl_Obj[] argv
)
{
sqlite3 db = null;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB MAGIC" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
if ( argv[2].ToString() == "SQLITE_MAGIC_OPEN" )
{
db.magic = SQLITE_MAGIC_OPEN;
}
else if ( argv[2].ToString() == "SQLITE_MAGIC_CLOSED" )
{
db.magic = SQLITE_MAGIC_CLOSED;
}
else if ( argv[2].ToString() == "SQLITE_MAGIC_BUSY" )
{
db.magic = SQLITE_MAGIC_BUSY;
}
else if ( argv[2].ToString() == "SQLITE_MAGIC_ERROR" )
{
db.magic = SQLITE_MAGIC_ERROR;
}
else if ( TCL.Tcl_GetInt( interp, argv[2], out db.magic ) )
{
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_interrupt DB
**
** Trigger an interrupt on DB
*/
static int test_interrupt(
object clientdata,
Tcl_Interp interp,
int argc,
Tcl_Obj[] argv )
{
sqlite3 db = null;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0], " DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
sqlite3_interrupt( db );
return TCL.TCL_OK;
}
 
//static u8 *sqlite3_stack_baseline = 0;
 
/*
** Fill the stack with a known bitpattern.
*/
//static void prepStack(void){
// int i;
// u32 bigBuf[65536];
// for(i=0; i<sizeof(bigBuf); i++) bigBuf[i] = 0xdeadbeef;
// sqlite3_stack_baseline = (u8)&bigBuf[65536];
//}
 
/*
** Get the current stack depth. Used for debugging only.
*/
//u64 sqlite3StackDepth(void){
// u8 x;
// return (u64)(sqlite3_stack_baseline - &x);
//}
 
/*
** Usage: sqlite3_stack_used DB SQL
**
** Try to measure the amount of stack space used by a call to sqlite3_exec
*/
//static int test_stack_used(
// object clientdata,
// Tcl_Interp interp,
// int argc,
// char **argv
//){
// sqlite3 db=null;
// int i;
// if( argc!=3 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " DB SQL", 0);
// return TCL.TCL_ERROR;
// }
// if( getDbPointer(interp, argv[1].ToString(), out db) !=0) return TCL.TCL_ERROR;
// prepStack();
// (void)sqlite3_exec(db, argv[2], 0, 0, 0);
// for(i=65535; i>=0 && ((u32)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){}
// TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(i*4));
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite_delete_function DB function-name
**
** Delete the user function 'function-name' from database handle DB. It
** is assumed that the user function was created as UTF8, any number of
** arguments (the way the TCL interface does it).
*/
static int delete_function(
object clientdata,
Tcl_Interp interp,
int argc,
Tcl_Obj[] argv
)
{
int rc;
sqlite3 db = null;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB function-name", null );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_create_function( db, argv[2].ToString(), -1, SQLITE_UTF8, null, null, null, null );
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), TCL.TCL_STATIC );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite_delete_collation DB collation-name
**
** Delete the collation sequence 'collation-name' from database handle
** DB. It is assumed that the collation sequence was created as UTF8 (the
** way the TCL interface does it).
*/
static int delete_collation(
object clientdata,
Tcl_Interp interp,
int argc,
Tcl_Obj[] argv
)
{
int rc;
sqlite3 db = null;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB function-name", null );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_create_collation( db, argv[2].ToString(), SQLITE_UTF8, null, null );
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), TCL.TCL_STATIC );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_get_autocommit DB
**
** Return true if the database DB is currently in auto-commit mode.
** Return false if not.
*/
static int get_autocommit(
object clientdata,
Tcl_Interp interp,
int argc,
Tcl_Obj[] argv
)
{
StringBuilder zBuf = new StringBuilder( 30 );
sqlite3 db = null;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
sqlite3_snprintf( 30, zBuf, "%d", sqlite3_get_autocommit( db ) );
TCL.Tcl_AppendResult( interp, zBuf );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_busy_timeout DB MS
**
** Set the busy timeout. This is more easily done using the timeout
** method of the TCL interface. But we need a way to test the case
** where it returns SQLITE_MISUSE.
*/
static int test_busy_timeout(
object clientdata,
Tcl_Interp interp,
int argc,
Tcl_Obj[] argv
)
{
int rc, ms = 0;
sqlite3 db = null;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, argv[1].ToString(), out db ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetInt( interp, argv[2], out ms ) )
return TCL.TCL_ERROR;
rc = sqlite3_busy_timeout( db, ms );
TCL.Tcl_AppendResult( interp, sqlite3TestErrorName( rc ) );
return TCL.TCL_OK;
}
 
/*
** Usage: tcl_variable_type VARIABLENAME
**
** Return the name of the internal representation for the
** value of the given variable.
*/
static int tcl_variable_type(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
Tcl_Obj pVar;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "VARIABLE" );
return TCL.TCL_ERROR;
}
pVar = TCL.Tcl_GetVar2Ex( interp, TCL.Tcl_GetString( objv[1] ), null, (TCL.VarFlag)TCL.TCL_LEAVE_ERR_MSG );
if ( pVar == null )
return TCL.TCL_ERROR;
if ( pVar.typePtr != "" )
{
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewStringObj( pVar.typePtr, -1 ) );
}
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_release_memory ?N?
**
** Attempt to release memory currently held but not actually required.
** The integer N is the number of bytes we are trying to release. The
** return value is the amount of memory actually released.
*/
static int test_release_memory(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if SQLITE_ENABLE_MEMORY_MANAGEMENT && !SQLITE_OMIT_DISKIO
int N;
int amt;
if( objc!=1 && objc!=2 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "?N?");
return TCL.TCL_ERROR;
}
if( objc==2 ){
if( TCL.Tcl_GetIntFromObj(interp, objv[1], out N) ) return TCL.TCL_ERROR;
}else{
N = -1;
}
amt = sqlite3_release_memory(N);
TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(amt));
#endif
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_soft_heap_limit ?N?
**
** Query or set the soft heap limit for the current thread. The
** limit is only changed if the N is present. The previous limit
** is returned.
*/
static int test_soft_heap_limit(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_int64 amt;
sqlite3_int64 N = -1;
if ( objc != 1 && objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "?N?" );
return TCL.TCL_ERROR;
}
if ( objc == 2 )
{
if ( TCL.Tcl_GetWideIntFromObj( interp, objv[1], out N ) )
return TCL.TCL_ERROR;
}
amt = sqlite3_soft_heap_limit64( N );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewWideIntObj( amt ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_thread_cleanup
**
** Call the sqlite3_thread_cleanup API.
*/
//static int test_thread_cleanup(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// sqlite3_thread_cleanup();
// return TCL.TCL_OK;
//}
 
 
/*
** Usage: sqlite3_pager_refcounts DB
**
** Return a list of numbers which are the PagerRefcount for all
** pagers on each database connection.
*/
//static int test_pager_refcounts(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// sqlite3 db=null;
// int i;
// int v, *a;
// Tcl_Obj pResult;
 
// if( objc!=2 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"",
// TCL.Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
// return TCL.TCL_ERROR;
// }
// if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
// pResult = TCL.Tcl_NewObj();
// for(i=0; i<db.nDb; i++){
// if( db.aDb[i].pBt==null ){
// v = -1;
// }else{
// sqlite3_mutex_enter(db.mutex);
// a = sqlite3PagerStats(sqlite3BtreePager(db.aDb[i].pBt));
// v = a[0];
// sqlite3_mutex_leave(db.mutex);
// }
// TCL.Tcl_ListObjAppendElement(0, pResult, TCL.Tcl_NewIntObj(v));
// }
// TCL.Tcl_SetObjResult(interp, pResult);
// return TCL.TCL_OK;
//}
 
 
/*
** tclcmd: working_64bit_int
**
** Some TCL builds (ex: cygwin) do not support 64-bit integers. This
** leads to a number of test failures. The present command checks the
** TCL build to see whether or not it supports 64-bit integers. It
** returns TRUE if it does and FALSE if not.
**
** This command is used to warn users that their TCL build is defective
** and that the errors they are seeing in the test scripts might be
** a result of their defective TCL rather than problems in SQLite.
*/
static int working_64bit_int(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
Tcl_Obj pTestObj;
int working = 0;
 
pTestObj = TCL.Tcl_NewWideIntObj( 1000000 * (i64)1234567890 );
working = ( TCL.Tcl_GetString( pTestObj ) == "1234567890000000" ) ? 1 : 0;
TCL.Tcl_DecrRefCount( ref pTestObj );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( working ) );
return TCL.TCL_OK;
}
 
 
/*
** tclcmd: vfs_unlink_test
**
** This TCL command unregisters the primary VFS and then registers
** it back again. This is used to test the ability to register a
** VFS when none are previously registered, and the ability to
** unregister the only available VFS. Ticket #2738
*/
static int vfs_unlink_test(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
int i;
sqlite3_vfs pMain;
sqlite3_vfs one = new sqlite3_vfs();
sqlite3_vfs two = new sqlite3_vfs();
 
sqlite3_vfs_unregister( null ); /* Unregister of NULL is harmless */
one.zName = "__one";
two.zName = "__two";
 
/* Calling sqlite3_vfs_register with 2nd argument of 0 does not
** change the default VFS
*/
pMain = sqlite3_vfs_find( null );
sqlite3_vfs_register( one, 0 );
Debug.Assert( pMain == null || pMain == sqlite3_vfs_find( null ) );
sqlite3_vfs_register( two, 0 );
Debug.Assert( pMain == null || pMain == sqlite3_vfs_find( null ) );
 
/* We can find a VFS by its name */
Debug.Assert( sqlite3_vfs_find( "__one" ) == one );
Debug.Assert( sqlite3_vfs_find( "__two" ) == two );
 
/* Calling sqlite_vfs_register with non-zero second parameter changes the
** default VFS, even if the 1st parameter is an existig VFS that is
** previously registered as the non-default.
*/
sqlite3_vfs_register( one, 1 );
Debug.Assert( sqlite3_vfs_find( "__one" ) == one );
Debug.Assert( sqlite3_vfs_find( "__two" ) == two );
Debug.Assert( sqlite3_vfs_find( null ) == one );
sqlite3_vfs_register( two, 1 );
Debug.Assert( sqlite3_vfs_find( "__one" ) == one );
Debug.Assert( sqlite3_vfs_find( "__two" ) == two );
Debug.Assert( sqlite3_vfs_find( null ) == two );
if ( pMain != null )
{
sqlite3_vfs_register( pMain, 1 );
Debug.Assert( sqlite3_vfs_find( "__one" ) == one );
Debug.Assert( sqlite3_vfs_find( "__two" ) == two );
Debug.Assert( sqlite3_vfs_find( null ) == pMain );
}
 
/* Unlink the default VFS. Repeat until there are no more VFSes
** registered.
*/
for ( i = 0; i < apVfs.Length; i++ )
{//sizeof(apVfs)/sizeof(apVfs[0]); i++){
apVfs[i] = sqlite3_vfs_find( null );
if ( apVfs[i] != null )
{
Debug.Assert( apVfs[i] == sqlite3_vfs_find( apVfs[i].zName ) );
sqlite3_vfs_unregister( apVfs[i] );
Debug.Assert( null == sqlite3_vfs_find( apVfs[i].zName ) );
}
}
Debug.Assert( null == sqlite3_vfs_find( null ) );
 
 
/* Register the main VFS as non-default (will be made default, since
** it'll be the only one in existence).
*/
sqlite3_vfs_register( pMain, 0 );
Debug.Assert( sqlite3_vfs_find( null ) == pMain );
 
/* Un-register the main VFS again to restore an empty VFS list */
sqlite3_vfs_unregister( pMain );
Debug.Assert( null == sqlite3_vfs_find( null ) );
 
/* Relink all VFSes in reverse order. */
for ( i = apVfs.Length - 1; i >= 0; i-- )
{//sizeof(apVfs)/sizeof(apVfs[0])-1; i>=0; i--){
if ( apVfs[i] != null )
{
sqlite3_vfs_register( apVfs[i], 1 );
Debug.Assert( apVfs[i] == sqlite3_vfs_find( null ) );
Debug.Assert( apVfs[i] == sqlite3_vfs_find( apVfs[i].zName ) );
}
}
 
/* Unregister out sample VFSes. */
sqlite3_vfs_unregister( one );
sqlite3_vfs_unregister( two );
 
/* Unregistering a VFS that is not currently registered is harmless */
sqlite3_vfs_unregister( one );
sqlite3_vfs_unregister( two );
Debug.Assert( sqlite3_vfs_find( "__one" ) == null );
Debug.Assert( sqlite3_vfs_find( "__two" ) == null );
 
/* We should be left with the original default VFS back as the
** original */
Debug.Assert( sqlite3_vfs_find( null ) == pMain );
 
return TCL.TCL_OK;
}
 
/*
** tclcmd: vfs_initfail_test
**
** This TCL command attempts to vfs_find and vfs_register when the
** sqlite3_initialize() interface is failing. All calls should fail.
*/
//static int vfs_initfail_test(
// ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int objc, /* Number of arguments */
// Tcl_Obj[] objv /* Command arguments */
//){
// sqlite3_vfs one;
// one.zName = "__one";
 
// if( sqlite3_vfs_find(0) ) return TCL.TCL_ERROR;
// sqlite3_vfs_register(&one, 0);
// if( sqlite3_vfs_find(0) ) return TCL.TCL_ERROR;
// sqlite3_vfs_register(&one, 1);
// if( sqlite3_vfs_find(0) ) return TCL.TCL_ERROR;
// return TCL.TCL_OK;
//}
 
 
/*
** Saved VFSes
*/
static sqlite3_vfs[] apVfs = new sqlite3_vfs[20];
static int nVfs = 0;
 
/*
** tclcmd: vfs_unregister_all
**
** Unregister all VFSes.
*/
static int vfs_unregister_all(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
int i;
for ( i = 0; i < apVfs.Length; i++ )
{
apVfs[i] = sqlite3_vfs_find( null );
if ( apVfs[i] == null )
break;
sqlite3_vfs_unregister( apVfs[i] );
}
nVfs = i;
return TCL.TCL_OK;
}
 
/*
** tclcmd: vfs_reregister_all
**
** Restore all VFSes that were removed using vfs_unregister_all
*/
static int vfs_reregister_all(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
int i;
for ( i = 0; i < nVfs; i++ )
{
sqlite3_vfs_register( apVfs[i], i == 0 ? 1 : 0 );
}
return TCL.TCL_OK;
}
 
 
/*
** tclcmd: file_control_test DB
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the same.
*/
static int file_control_test(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3_int64 iArg = 0;
sqlite3 db = null;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_file_control( db, null, 0, ref iArg );
Debug.Assert( rc == SQLITE_NOTFOUND );
rc = sqlite3_file_control( db, "notadatabase", SQLITE_FCNTL_LOCKSTATE, ref iArg );
Debug.Assert( rc == SQLITE_ERROR );
rc = sqlite3_file_control( db, "main", -1, ref iArg );
Debug.Assert( rc == SQLITE_NOTFOUND );
rc = sqlite3_file_control( db, "temp", -1, ref iArg );
Debug.Assert( rc == SQLITE_NOTFOUND || rc == SQLITE_ERROR );
return TCL.TCL_OK;
}
 
 
/*
** tclcmd: file_control_lasterrno_test DB
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_LAST_ERRNO verb.
*/
static int file_control_lasterrno_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3_int64 iArg = 0;
sqlite3 db = null;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
{
return TCL.TCL_ERROR;
}
rc = sqlite3_file_control( db, null, SQLITE_LAST_ERRNO, ref iArg );
if ( rc != 0 )
{
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return TCL.TCL_ERROR;
}
if ( iArg != 0 )
{
TCL.Tcl_AppendResult( interp, "Unexpected non-zero errno: ", iArg.ToString(), "" );
//TCL.Tcl_GetStringFromObj(TCL.Tcl_NewIntObj(iArg), 0), " ", 0);
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
 
/*
** tclcmd: file_control_chunksize_test DB DBNAME SIZE
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/
static int file_control_chunksize_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
int nSize = 0; /* New chunk size */
string zDb; /* Db name ("main", "temp" etc.) */
sqlite3 db = null; /* Database handle */
int rc; /* file_control() return code */
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB DBNAME SIZE" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0
|| TCL.Tcl_GetIntFromObj( interp, objv[3], out nSize ) != 0
)
{
return TCL.TCL_ERROR;
}
zDb = TCL.Tcl_GetString( objv[2] );
if ( zDb == "" )
zDb = null;
 
i64 iSize = 0;
rc = sqlite3_file_control( db, zDb, SQLITE_FCNTL_CHUNK_SIZE, ref iSize );
nSize = (int)iSize;
 
if ( rc != 0 )
{
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_STATIC );
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
 
 
/*
** tclcmd: file_control_sizehint_test DB DBNAME SIZE
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/
static int file_control_sizehint_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3_int64 nSize = 0; /* Hinted size */
string zDb; /* Db name ("main", "temp" etc.) */
sqlite3 db = null; /* Database handle */
int rc; /* file_control() return code */
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB DBNAME SIZE" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0
|| TCL.Tcl_GetWideIntFromObj( interp, objv[3], out nSize )
)
{
return TCL.TCL_ERROR;
}
zDb = TCL.Tcl_GetString( objv[2] );
if ( zDb[0] == '\0' )
zDb = null;
 
rc = sqlite3_file_control( db, zDb, SQLITE_FCNTL_SIZE_HINT, ref nSize );
if ( rc != 0 )
{
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_STATIC );
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
/*
** tclcmd: file_control_lockproxy_test DB PWD
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/
static int file_control_lockproxy_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
string zPwd;
int nPwd = 0;
 
if ( objc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " DB PWD" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
{
return TCL.TCL_ERROR;
}
zPwd = TCL.Tcl_GetStringFromObj( objv[2], out nPwd );
 
//#if !(SQLITE_ENABLE_LOCKING_STYLE) && (__APPLE__)
//{
// char *testPath;
// int rc;
// char proxyPath[400];
 
// if( sizeof(proxyPath)<nPwd+20 ){
// TCL.Tcl_AppendResult(interp, "PWD too big", (void)0);
// return TCL.TCL_ERROR;
// }
// sprintf(proxyPath, "%s/test.proxy", zPwd);
// rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
// if( rc ){
// TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(rc));
// return TCL.TCL_ERROR;
// }
// rc = sqlite3_file_control(db, NULL, SQLITE_GET_LOCKPROXYFILE, &testPath);
// if( strncmp(proxyPath,testPath,11) ){
// TCL.Tcl_AppendResult(interp, "Lock proxy file did not match the "
// "previously assigned value", 0);
// return TCL.TCL_ERROR;
// }
// if( rc ){
// TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(rc));
// return TCL.TCL_ERROR;
// }
// rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
// if( rc ){
// TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(rc));
// return TCL.TCL_ERROR;
// }
//}
//#endif
return TCL.TCL_OK;
}
 
/*
** tclcmd: sqlite3_vfs_list
**
** Return a tcl list containing the names of all registered vfs's.
*/
//static int vfs_list(
// ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int objc, /* Number of arguments */
// Tcl_Obj[] objv /* Command arguments */
//){
// sqlite3_vfs pVfs;
// Tcl_Obj pRet = TCL.Tcl_NewObj();
// if( objc!=1 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "");
// return TCL.TCL_ERROR;
// }
// for(pVfs=sqlite3_vfs_find(0); pVfs!=null; pVfs=pVfs.pNext){
// TCL.Tcl_ListObjAppendElement(interp, pRet, TCL.Tcl_NewStringObj(pVfs.zName, -1));
// }
// TCL.Tcl_SetObjResult(interp, pRet);
// return TCL.TCL_OK;
//}
 
/*
** tclcmd: sqlite3_limit DB ID VALUE
**
** This TCL command runs the sqlite3_limit interface and
** verifies correct operation of the same.
*/
struct _aID
{
public string zName;
public int id;
public _aID( string zName, int id )
{
this.zName = zName;
this.id = id;
}
}
 
static int test_limit(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
int rc = 0;
_aID[] aId = new _aID[] {
new _aID( "SQLITE_LIMIT_LENGTH", SQLITE_LIMIT_LENGTH ),
new _aID( "SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH ),
new _aID( "SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN ),
new _aID( "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH ),
new _aID( "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT ),
new _aID( "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP ),
new _aID( "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG ),
new _aID( "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED ),
new _aID( "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH ),
new _aID( "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER ),
new _aID( "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH ),
 
/* Out of range test cases */
new _aID( "SQLITE_LIMIT_TOOSMALL", -1 ),
new _aID( "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_TRIGGER_DEPTH+1 ),
};
int i, id = 0;
int val = 0;
string zId;
 
if ( objc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"",
TCL.Tcl_GetStringFromObj( objv[0], 0 ), " DB ID VALUE" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
zId = TCL.Tcl_GetString( objv[2] );
for ( i = 0; i < aId.Length; i++ )
{
if ( zId == aId[i].zName )
{
id = aId[i].id;
break;
}
}
if ( i >= aId.Length )
{
TCL.Tcl_AppendResult( interp, "unknown limit type: ", zId, '\0' );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out val ) )
return TCL.TCL_ERROR;
rc = sqlite3_limit( db, id, val );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return TCL.TCL_OK;
}
 
/*
** tclcmd: save_prng_state
**
** Save the state of the pseudo-random number generator.
** At the same time, verify that sqlite3_test_control works even when
** called with an out-of-range opcode.
*/
static int save_prng_state(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
int rc = sqlite3_test_control( 9999 );
Debug.Assert( rc == 0 );
rc = sqlite3_test_control( -1 );
Debug.Assert( rc == 0 );
sqlite3_test_control( SQLITE_TESTCTRL_PRNG_SAVE );
return TCL.TCL_OK;
}
/*
** tclcmd: restore_prng_state
*/
static int restore_prng_state(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3_test_control( SQLITE_TESTCTRL_PRNG_RESTORE );
return TCL.TCL_OK;
}
/*
** tclcmd: reset_prng_state
*/
static int reset_prng_state(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3_test_control( SQLITE_TESTCTRL_PRNG_RESET );
return TCL.TCL_OK;
}
 
 
/*
** tclcmd: pcache_stats
*/
static int test_pcache_stats(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
int nMin;
int nMax;
int nCurrent;
int nRecyclable;
Tcl_Obj pRet;
 
sqlite3PcacheStats( out nCurrent, out nMax, out nMin, out nRecyclable );
 
pRet = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewStringObj( "current", -1 ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( nCurrent ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewStringObj( "max", -1 ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( nMax ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewStringObj( "min", -1 ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( nMin ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewStringObj( "recyclable", -1 ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( nRecyclable ) );
 
TCL.Tcl_SetObjResult( interp, pRet );
 
return TCL.TCL_OK;
}
 
 
 
public class _aObjCmd
{
public string zName;
public Interp.dxObjCmdProc xProc;
public object clientData;
public _aObjCmd( string zName, Interp.dxObjCmdProc xProc )
{
this.zName = zName;
this.xProc = xProc;
this.clientData = null;
}
public _aObjCmd( string zName, Interp.dxObjCmdProc xProc, object clientdata )
{
this.zName = zName;
this.xProc = xProc;
this.clientData = clientdata.GetType().Name == "Int32" && (int)clientdata == 0 ? null : clientdata;
}
}
 
#if SQLITE_ENABLE_UNLOCK_NOTIFY
static void test_unlock_notify_cb(void **aArg, int nArg){
int ii;
for(ii=0; ii<nArg; ii++){
TCL.Tcl_EvalEx((Tcl_Interp )aArg[ii], "unlock_notify", -1, TCL.TCL_EVAL_GLOBAL);
}
}
#endif //* SQLITE_ENABLE_UNLOCK_NOTIFY */
 
/*
** tclcmd: sqlite3_unlock_notify db
*/
#if SQLITE_ENABLE_UNLOCK_NOTIFY
static int test_unlock_notify(
ClientData clientData, /* Unused */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
){
sqlite3 db;
int rc;
 
if( objc!=2 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL.TCL_ERROR;
}
 
if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), &db) ){
return TCL.TCL_ERROR;
}
rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void )interp);
TCL.Tcl_SetResult(interp, (char )t1ErrorName(rc), TCL.TCL_STATIC);
return TCL.TCL_OK;
}
#endif
 
/*
** tclcmd: sqlite3_wal_checkpoint db ?NAME?
*/
static int test_wal_checkpoint(
ClientData clientData, /* Unused */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
string zDb = "";
sqlite3 db = null;
int rc;
 
if ( objc != 3 && objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB ?NAME?" );
return TCL.TCL_ERROR;
}
 
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
{
return TCL.TCL_ERROR;
}
if ( objc == 3 )
{
zDb = TCL.Tcl_GetString( objv[2] );
}
rc = sqlite3_wal_checkpoint( db, zDb );
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), TCL.TCL_STATIC );
return TCL.TCL_OK;
}
 
/*
** tclcmd: sqlite3_wal_checkpoint_v2 db MODE ?NAME?
**
** This command calls the wal_checkpoint_v2() function with the specified
** mode argument (passive, full or restart). If present, the database name
** NAME is passed as the second argument to wal_checkpoint_v2(). If it the
** NAME argument is not present, a NULL pointer is passed instead.
**
** If wal_checkpoint_v2() returns any value other than SQLITE_BUSY or
** SQLITE_OK, then this command returns TCL_ERROR. The Tcl result is set
** to the error message obtained from sqlite3_errmsg().
**
** Otherwise, this command returns a list of three integers. The first integer
** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers
** are the values returned via the output paramaters by wal_checkpoint_v2() -
** the number of frames in the log and the number of frames in the log
** that have been checkpointed.
*/
static int test_wal_checkpoint_v2(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
string zDb = "";
sqlite3 db = null;
int rc;
 
int eMode = 0;
int nLog = -555;
int nCkpt = -555;
Tcl_Obj pRet;
 
string[] aMode = new string[] { "passive", "full", "restart" };
Debug.Assert( SQLITE_CHECKPOINT_PASSIVE == 0 );
Debug.Assert( SQLITE_CHECKPOINT_FULL == 1 );
Debug.Assert( SQLITE_CHECKPOINT_RESTART == 2 );
 
if ( objc != 3 && objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB MODE ?NAME?" );
return TCL.TCL_ERROR;
}
 
if ( objc == 4 )
{
zDb = TCL.Tcl_GetString( objv[3] );
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0
|| TCL.Tcl_GetIndexFromObj( interp, objv[2], aMode, "mode", 0, out eMode )
)
{
return TCL.TCL_ERROR;
}
 
rc = sqlite3_wal_checkpoint_v2( db, zDb, eMode, out nLog, out nCkpt );
if ( rc != SQLITE_OK && rc != SQLITE_BUSY )
{
TCL.Tcl_SetResult( interp, sqlite3_errmsg( db ), TCL.TCL_VOLATILE );
return TCL.TCL_ERROR;
}
 
pRet = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( rc == SQLITE_BUSY ? 1 : 0 ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( nLog ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( nCkpt ) );
TCL.Tcl_SetObjResult( interp, pRet );
 
return TCL.TCL_OK;
}
 
/*
** tclcmd: test_sqlite3_log ?SCRIPT?
*/
struct LogCallback
{
public Tcl_Interp pInterp;
public Tcl_Obj pObj;
}
static LogCallback logcallback = new LogCallback();
 
static void xLogcallback( object unused, int err, string zMsg )
{
Tcl_Obj pNew = TCL.Tcl_DuplicateObj( logcallback.pObj );
TCL.Tcl_IncrRefCount( pNew );
TCL.Tcl_ListObjAppendElement(
null, pNew, TCL.Tcl_NewStringObj( sqlite3TestErrorName( err ), -1 )
);
TCL.Tcl_ListObjAppendElement( null, pNew, TCL.Tcl_NewStringObj( zMsg, -1 ) );
TCL.Tcl_EvalObjEx( logcallback.pInterp, pNew, TCL.TCL_EVAL_GLOBAL | TCL.TCL_EVAL_DIRECT );
TCL.Tcl_DecrRefCount( ref pNew );
}
 
static int test_sqlite3_log(
ClientData clientData,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
if ( objc > 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SCRIPT" );
return TCL.TCL_ERROR;
}
if ( logcallback.pObj != null )
{
TCL.Tcl_DecrRefCount( ref logcallback.pObj );
logcallback.pObj = null;
logcallback.pInterp = null;
sqlite3_config( SQLITE_CONFIG_LOG, 0, 0 );
}
if ( objc > 1 )
{
logcallback.pObj = objv[1];
TCL.Tcl_IncrRefCount( logcallback.pObj );
logcallback.pInterp = interp;
sqlite3_config( SQLITE_CONFIG_LOG, (dxLogcallback)xLogcallback, 0 );
}
return TCL.TCL_OK;
}
 
 
/*
** tcl_objproc COMMANDNAME ARGS...
**
** Run a TCL command using its objProc interface. Throw an error if
** the command has no objProc interface.
*/
//static int runAsObjProc(
// void * clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// TCL.Tcl_CmdInfo cmdInfo;
// if( objc<2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "COMMAND ...");
// return TCL.TCL_ERROR;
// }
// if( null==TCL.Tcl_GetCommandInfo(interp, TCL.Tcl_GetString(objv[1]), &cmdInfo) ){
// TCL.Tcl_AppendResult(interp, "command not found: ",
// TCL.Tcl_GetString(objv[1]), (char)0);
// return TCL.TCL_ERROR;
// }
// if( cmdInfo.objProc==0 ){
// TCL.Tcl_AppendResult(interp, "command has no objProc: ",
// TCL.Tcl_GetString(objv[1]), (char)0);
// return TCL.TCL_ERROR;
// }
// return cmdInfo.objProc(cmdInfo.objClientData, interp, objc-1, objv+1);
//}
 
/*
** Register commands with the TCL interpreter.
*/
 
#if !SQLITE_OMIT_EXPLAIN
/*
** WARNING: The following function, printExplainQueryPlan() is an exact
** copy of example code from eqp.in (eqp.html). If this code is modified,
** then the documentation copy needs to be modified as well.
*/
/*
** Argument pStmt is a prepared SQL statement. This function compiles
** an EXPLAIN QUERY PLAN command to report on the prepared statement,
** and prints the report to stdout using printf().
*/
static int printExplainQueryPlan( sqlite3_stmt pStmt )
{
string zSql; /* Input SQL */
string zExplain; /* SQL with EXPLAIN QUERY PLAN prepended */
sqlite3_stmt pExplain = null; /* Compiled EXPLAIN QUERY PLAN command */
int rc; /* Return code from sqlite3_prepare_v2() */
 
zSql = sqlite3_sql( pStmt );
if ( zSql == null )
return SQLITE_ERROR;
 
zExplain = sqlite3_mprintf( "EXPLAIN QUERY PLAN %s", zSql );
//if ( zExplain == null )
// return SQLITE_NOMEM;
 
rc = sqlite3_prepare_v2( sqlite3_db_handle( pStmt ), zExplain, -1, ref pExplain, 0 );
//sqlite3_free(zExplain);
if ( rc != SQLITE_OK )
return rc;
 
while ( SQLITE_ROW == sqlite3_step( pExplain ) )
{
int iSelectid = sqlite3_column_int( pExplain, 0 );
int iOrder = sqlite3_column_int( pExplain, 1 );
int iFrom = sqlite3_column_int( pExplain, 2 );
string zDetail = sqlite3_column_text( pExplain, 3 );
 
printf( "%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail );
}
 
return sqlite3_finalize( pExplain );
}
 
static int test_print_eqp(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc;
sqlite3_stmt pStmt = null;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "STMT" );
return TCL.TCL_ERROR;
}
if ( getStmtPointer( interp, TCL.Tcl_GetString( objv[1] ), out pStmt ) != 0 )
return TCL.TCL_ERROR;
rc = printExplainQueryPlan( pStmt );
/* This is needed on Windows so that a test case using this
** function can open a read pipe and get the output of
** printExplainQueryPlan() immediately.
*/
//fflush( stdout );
TCL.Tcl_SetResult( interp, t1ErrorName( rc ), 0 );
return TCL.TCL_OK;
}
#endif //* SQLITE_OMIT_EXPLAIN */
 
class Verb
{
public string zName;
public int i;
 
public Verb( string zName, int i )
{
this.zName = zName;
this.i = i;
}
}
 
/*
** sqlite3_test_control VERB ARGS...
*/
static int test_test_control(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
Verb[] aVerb = new Verb[] {
new Verb( "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT ),
};
int iVerb;
int iFlag;
int rc;
 
if ( objc < 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "VERB ARGS..." );
return TCL.TCL_ERROR;
}
 
//rc = TCL.Tcl_GetIndexFromObjStruct(
// interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb
//);
for ( iVerb = 0; iVerb < aVerb.Length && ( aVerb[iVerb].zName != objv[1].ToString() ); iVerb++ )
{
}
if ( iVerb >= aVerb.Length )
return TCL.TCL_ERROR;
 
iFlag = aVerb[iVerb].i;
switch ( iFlag )
{
case SQLITE_TESTCTRL_LOCALTIME_FAULT:
{
bool val = false;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, "ONOFF" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[2], out val ) )
return TCL.TCL_ERROR;
sqlite3_test_control( SQLITE_TESTCTRL_LOCALTIME_FAULT, val );
break;
}
}
 
TCL.Tcl_ResetResult( interp );
return TCL.TCL_OK;
}
 
/*
** optimization_control DB OPT BOOLEAN
**
** Enable or disable query optimizations using the sqlite3_test_control()
** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true.
** OPT is the name of the optimization to be disabled.
*/
public class _aOpt
{
public string zOptName;
public int mask;
 
public _aOpt( string zOptName, int mask )
{
this.zOptName = zOptName;
this.mask = mask;
}
}
 
static int optimization_control(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int i;
sqlite3 db = null;
string zOpt;
bool onoff = false;
int mask = 0;
_aOpt[] aOpt = {
new _aOpt( "all", SQLITE_OptMask ),
new _aOpt( "query-flattener", SQLITE_QueryFlattener ),
new _aOpt( "column-cache", SQLITE_ColumnCache ),
new _aOpt( "index-sort", SQLITE_IndexSort ),
new _aOpt( "index-search", SQLITE_IndexSearch ),
new _aOpt( "index-cover", SQLITE_IndexCover ),
new _aOpt( "groupby-order", SQLITE_GroupByOrder ),
new _aOpt( "factor-constants", SQLITE_FactorOutConst ),
new _aOpt( "real-as-int", SQLITE_IdxRealAsInt ),
};
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB OPT BOOLEAN" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[3], out onoff ) )
return TCL.TCL_ERROR;
zOpt = TCL.Tcl_GetString( objv[2] );
for ( i = 0; i < aOpt.Length; i++ )//sizeof(aOpt)/sizeof(aOpt[0]); i++)
{
if ( zOpt == aOpt[i].zOptName )
{
mask = aOpt[i].mask;
break;
}
}
if ( onoff )
mask = ~mask;
if ( i >= aOpt.Length )//sizeof(aOpt)/sizeof(aOpt[0]) )
{
TCL.Tcl_AppendResult( interp, "unknown optimization - should be one of:",
null );
for ( i = 0; i < aOpt.Length; i++ )//sizeof(aOpt)/sizeof(aOpt[0]); i++)
{
TCL.Tcl_AppendResult( interp, " ", aOpt[i].zOptName );
}
return TCL.TCL_ERROR;
}
sqlite3_test_control( SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask );
return TCL.TCL_OK;
}
 
 
static Var.SQLITE3_GETSET bitmask_size = new Var.SQLITE3_GETSET( "bitmask_size" );
 
#if SQLITE_OS_UNIX && (__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
extern int sqlite3_hostid_num;
#endif
static Var.SQLITE3_GETSET sqlite_static_bind_nbyte = new Var.SQLITE3_GETSET( "static_bind_nbyte" );
static Var.SQLITE3_GETSET sqlite_static_bind_value = new Var.SQLITE3_GETSET( "static_bind_value" );
 
public static int Sqlitetest1_Init( Tcl_Interp interp )
{
// extern int sqlite3_search_count;
// extern int sqlite3_found_count;
// extern int sqlite3_interrupt_count;
// extern int sqlite3_sort_count;
// extern int sqlite3_current_time;
// extern int sqlite3_max_blobsize;
// extern int sqlite3BtreeSharedCacheReport(void*,
// Tcl_Interp *,int,Tcl_Obj*CONST);
// static struct {
// string zName;
// TCL.Tcl_CmdProc *xProc;
_aCmd[] aCmd = new _aCmd[] {
new _aCmd( "db_enter", db_enter ),
new _aCmd( "db_leave", db_leave ),
new _aCmd( "sqlite3_mprintf_int", sqlite3_mprintf_int ),
new _aCmd( "sqlite3_mprintf_int64", sqlite3_mprintf_int64 ),
new _aCmd( "sqlite3_mprintf_long", sqlite3_mprintf_long ),
new _aCmd( "sqlite3_mprintf_str", sqlite3_mprintf_str ),
new _aCmd( "sqlite3_snprintf_str", sqlite3_snprintf_str ),
new _aCmd( "sqlite3_mprintf_stronly", sqlite3_mprintf_stronly),
new _aCmd( "sqlite3_mprintf_double", sqlite3_mprintf_double ),
new _aCmd( "sqlite3_mprintf_scaled", sqlite3_mprintf_scaled ),
new _aCmd( "sqlite3_mprintf_hexdouble", sqlite3_mprintf_hexdouble),
new _aCmd( "sqlite3_mprintf_z_test", test_mprintf_z ),
new _aCmd( "sqlite3_mprintf_n_test", test_mprintf_n ),
new _aCmd( "sqlite3_snprintf_int", test_snprintf_int ),
// new _aCmd( "sqlite3_last_insert_rowid", test_last_rowid ),
new _aCmd( "sqlite3_exec_printf", test_exec_printf ),
new _aCmd( "sqlite3_exec_hex", test_exec_hex ),
new _aCmd( "sqlite3_exec", test_exec ),
new _aCmd( "sqlite3_exec_nr", test_exec_nr ),
#if !SQLITE_OMIT_GET_TABLE
new _aCmd( "sqlite3_get_table_printf", test_get_table_printf ),
#endif
new _aCmd( "sqlite3_close", sqlite_test_close ),
new _aCmd( "sqlite3_create_function", test_create_function ),
new _aCmd( "sqlite3_create_aggregate", test_create_aggregate ),
new _aCmd( "sqlite_register_test_function", test_register_func ),
// new _aCmd( "sqlite_abort", sqlite_abort ),
new _aCmd( "sqlite_bind", test_bind ),
new _aCmd( "breakpoint", test_breakpoint ),
new _aCmd( "sqlite3_key", test_key ),
new _aCmd( "sqlite3_rekey", test_rekey ),
new _aCmd( "sqlite_set_magic", sqlite_set_magic ),
new _aCmd( "sqlite3_interrupt", test_interrupt ),
new _aCmd( "sqlite_delete_function", delete_function ),
new _aCmd( "sqlite_delete_collation", delete_collation ),
new _aCmd( "sqlite3_get_autocommit", get_autocommit ),
// new _aCmd( "sqlite3_stack_used", test_stack_used ),
new _aCmd( "sqlite3_busy_timeout", test_busy_timeout ),
// new _aCmd( "printf", test_printf ),
// new _aCmd( "sqlite3IoTrace", test_io_trace ),
};
// static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
// void *object;
_aObjCmd[] aObjCmd = new _aObjCmd[]{
new _aObjCmd( "sqlite3_connection_pointer", get_sqlite_pointer, 0 ),
new _aObjCmd( "sqlite3_bind_int", test_bind_int, 0 ),
new _aObjCmd( "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 ),
new _aObjCmd( "sqlite3_bind_int64", test_bind_int64, 0 ),
new _aObjCmd( "sqlite3_bind_double", test_bind_double, 0 ),
new _aObjCmd( "sqlite3_bind_null", test_bind_null ,0 ),
new _aObjCmd( "sqlite3_bind_text", test_bind_text ,0 ),
new _aObjCmd( "sqlite3_bind_text16", test_bind_text16 ,0 ),
new _aObjCmd( "sqlite3_bind_blob", test_bind_blob ,0 ),
new _aObjCmd( "sqlite3_bind_parameter_count", test_bind_parameter_count, 0),
new _aObjCmd( "sqlite3_bind_parameter_name", test_bind_parameter_name, 0),
new _aObjCmd( "sqlite3_bind_parameter_index", test_bind_parameter_index, 0),
new _aObjCmd( "sqlite3_clear_bindings", test_clear_bindings, 0),
new _aObjCmd( "sqlite3_sleep", test_sleep, 0),
new _aObjCmd( "sqlite3_errcode", test_errcode ,0 ),
new _aObjCmd( "sqlite3_extended_errcode", test_ex_errcode ,0 ),
new _aObjCmd( "sqlite3_errmsg", test_errmsg ,0 ),
// new _aObjCmd( "sqlite3_errmsg16", test_errmsg16 ,0 ),
new _aObjCmd( "sqlite3_open", test_open ,0 ),
// new _aObjCmd( "sqlite3_open16", test_open16 ,0 ),
new _aObjCmd( "sqlite3_open_v2", test_open_v2 ,0 ),
// new _aObjCmd( "sqlite3_complete16", test_complete16 ,0 ),
 
new _aObjCmd( "sqlite3_prepare", test_prepare ,0 ),
new _aObjCmd( "sqlite3_prepare16", test_prepare16 ,0 ),
new _aObjCmd( "sqlite3_prepare_v2", test_prepare_v2 ,0 ),
new _aObjCmd( "sqlite3_prepare_tkt3134", test_prepare_tkt3134, 0),
// new _aObjCmd( "sqlite3_prepare16_v2", test_prepare16_v2 ,0 ),
new _aObjCmd( "sqlite3_finalize", test_finalize ,0 ),
new _aObjCmd( "sqlite3_reset", test_reset ,0 ),
new _aObjCmd( "sqlite3_expired", test_expired ,0 ),
new _aObjCmd( "sqlite3_transfer_bindings", test_transfer_bind ,0 ),
new _aObjCmd( "sqlite3_changes", test_changes ,0 ),
new _aObjCmd( "sqlite3_step", test_step ,0 ),
// { "sqlite3_sql", test_sql ,0 },
new _aObjCmd( "sqlite3_next_stmt", test_next_stmt ,0 ),
new _aObjCmd( "sqlite3_stmt_readonly", test_stmt_readonly ,0 ),
new _aObjCmd( "uses_stmt_journal", uses_stmt_journal ,0 ),
 
new _aObjCmd( "sqlite3_release_memory", test_release_memory, 0),
new _aObjCmd( "sqlite3_soft_heap_limit", test_soft_heap_limit, 0),
// new _aObjCmd( "sqlite3_thread_cleanup", test_thread_cleanup, 0),
// new _aObjCmd( "sqlite3_pager_refcounts", test_pager_refcounts, 0),
 
// new _aObjCmd( "sqlite3_load_extension", test_load_extension, 0),
// new _aObjCmd( "sqlite3_enable_load_extension", test_enable_load, 0),
new _aObjCmd( "sqlite3_extended_result_codes", test_extended_result_codes, 0),
new _aObjCmd( "sqlite3_limit", test_limit, 0),
 
new _aObjCmd( "save_prng_state", save_prng_state, 0 ),
new _aObjCmd( "restore_prng_state", restore_prng_state, 0 ),
new _aObjCmd( "reset_prng_state", reset_prng_state, 0 ),
new _aObjCmd( "optimization_control", optimization_control,0),
// { "tcl_objproc", runAsObjProc, 0 },
 
// /* sqlite3_column_*() API */
new _aObjCmd( "sqlite3_column_count", test_column_count ,0 ),
new _aObjCmd( "sqlite3_data_count", test_data_count ,0 ),
new _aObjCmd( "sqlite3_column_type", test_column_type ,0 ),
new _aObjCmd( "sqlite3_column_blob", test_column_blob ,0 ),
new _aObjCmd( "sqlite3_column_double", test_column_double ,0 ),
new _aObjCmd( "sqlite3_column_int64", test_column_int64 ,0 ),
new _aObjCmd( "sqlite3_column_text", test_stmt_utf8, (dxColumn)sqlite3_column_text ),
new _aObjCmd( "sqlite3_column_name", test_stmt_utf8, (dxColumn)sqlite3_column_name ),
new _aObjCmd( "sqlite3_column_int", test_stmt_int, (dxColumn_I)sqlite3_column_int ),
new _aObjCmd( "sqlite3_column_bytes", test_stmt_int, (dxColumn_I)sqlite3_column_bytes ),
#if !SQLITE_OMIT_DECLTYPE
new _aObjCmd( "sqlite3_column_decltype", test_stmt_utf8, (dxColumn) sqlite3_column_decltype ),
#endif
#if SQLITE_ENABLE_COLUMN_METADATA
new _aObjCmd( "sqlite3_column_database_name", test_stmt_utf8, (dxColumn)sqlite3_column_database_name),
new _aObjCmd( "sqlite3_column_table_name", test_stmt_utf8, (dxColumn)sqlite3_column_table_name),
new _aObjCmd( "sqlite3_column_origin_name", test_stmt_utf8, (dxColumn)sqlite3_column_origin_name),
#endif
 
#if !SQLITE_OMIT_UTF16
// { "sqlite3_column_bytes16", test_stmt_int, sqlite3_column_bytes16 ),
// { "sqlite3_column_text16", test_stmt_utf16, sqlite3_column_text16 ),
// { "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16),
// { "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16 ),
// { "add_alignment_test_collations", add_alignment_test_collations, 0 ),
#if SQLITE_ENABLE_COLUMN_METADATA
//{"sqlite3_column_database_name16",
// test_stmt_utf16, sqlite3_column_database_name16),
//{"sqlite3_column_table_name16", test_stmt_utf16, sqlite3_column_table_name16),
//{"sqlite3_column_origin_name16", test_stmt_utf16, sqlite3_column_origin_name16),
#endif
#endif
new _aObjCmd( "sqlite3_create_collation_v2", test_create_collation_v2, 0 ),
new _aObjCmd( "sqlite3_global_recover", test_global_recover, 0 ),
new _aObjCmd( "working_64bit_int", working_64bit_int, 0 ),
new _aObjCmd( "vfs_unlink_test", vfs_unlink_test, 0 ),
//{ "vfs_initfail_test", vfs_initfail_test, 0 },
new _aObjCmd( "vfs_unregister_all", vfs_unregister_all, 0 ),
new _aObjCmd("vfs_reregister_all", vfs_reregister_all, 0 ),
new _aObjCmd( "file_control_test", file_control_test, 0 ),
new _aObjCmd("file_control_lasterrno_test", file_control_lasterrno_test, 0 ),
new _aObjCmd("file_control_lockproxy_test", file_control_lockproxy_test, 0 ),
new _aObjCmd("file_control_chunksize_test", file_control_chunksize_test, 0 ),
new _aObjCmd("file_control_sizehint_test", file_control_sizehint_test, 0),
//new _aObjCmd( "sqlite3_vfs_list", vfs_list, 0 ),
new _aObjCmd( "sqlite3_create_function_v2", test_create_function_v2, 0 ),
 
// /* Functions from os.h */
#if !SQLITE_OMIT_UTF16
// { "add_test_collate", test_collate, 0 ),
// { "add_test_collate_needed", test_collate_needed, 0 ),
// { "add_test_function", test_function, 0 ),
#endif
new _aObjCmd( "sqlite3_test_errstr", test_errstr, 0 ),
new _aObjCmd( "tcl_variable_type", tcl_variable_type, 0 ),
#if !SQLITE_OMIT_SHARED_CACHE
new _aObjCmd( "sqlite3_enable_shared_cache", test_enable_shared, 0 ),
//{ "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0),
#endif
new _aObjCmd( "sqlite3_libversion_number", test_libversion_number, 0 ),
#if SQLITE_ENABLE_COLUMN_METADATA
new _aObjCmd( "sqlite3_table_column_metadata", test_table_column_metadata, 0 ),
#endif
#if !SQLITE_OMIT_INCRBLOB
// new _aObjCmd( "sqlite3_blob_read", test_blob_read, 0 ),
// new _aObjCmd( "sqlite3_blob_write", test_blob_write, 0 ),
//{ "sqlite3_blob_reopen", test_blob_reopen, 0 },
//{ "sqlite3_blob_bytes", test_blob_bytes, 0 },
//{ "sqlite3_blob_close", test_blob_close, 0 },
#endif
new _aObjCmd( "pcache_stats", test_pcache_stats, 0 ),
#if SQLITE_ENABLE_UNLOCK_NOTIFY
{ "sqlite3_unlock_notify", test_unlock_notify, 0 },
#endif
new _aObjCmd( "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 ),
new _aObjCmd( "sqlite3_wal_checkpoint_v2", test_wal_checkpoint_v2, 0 ),
new _aObjCmd( "test_sqlite3_log", test_sqlite3_log, 0 ),
#if !SQLITE_OMIT_EXPLAIN
new _aObjCmd( "print_explain_query_plan", test_print_eqp, 0 ),
#endif
new _aObjCmd( "sqlite3_test_control", test_test_control ),
};
bitmask_size.iValue = BMS;
int i;
// extern int sqlite3_sync_count, sqlite3_fullsync_count;
// extern int sqlite3_opentemp_count;
// extern int sqlite3_like_count;
// extern int sqlite3_xferopt_count;
// extern int sqlite3_pager_readdb_count;
// extern int sqlite3_pager_writedb_count;
// extern int sqlite3_pager_writej_count;
#if SQLITE_OS_WIN
// extern int sqlite3_os_type;
#endif
#if SQLITE_DEBUG
// extern int sqlite3WhereTrace;
// extern int sqlite3OSTrace;
// extern int sqlite3VdbeAddopTrace;
// extern int sqlite3WalTrace;
#endif
#if SQLITE_TEST
// extern char sqlite3_query_plan[];
// static char *query_plan = sqlite3_query_plan;
#if SQLITE_ENABLE_FTS3
extern int sqlite3_fts3_enable_parentheses;
#endif
#endif
 
for ( i = 0; i < aCmd.Length; i++ )
{//sizeof(aCmd)/sizeof(aCmd[0]); i++){
TCL.Tcl_CreateCommand( interp, aCmd[i].zName, aCmd[i].xProc, null, null );
}
for ( i = 0; i < aObjCmd.Length; i++ )
{// i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
(Interp.dxObjCmdProc)aObjCmd[i].xProc, (object)aObjCmd[i].clientData, null );
}
TCL.Tcl_LinkVar( interp, "sqlite_search_count",
sqlite3_search_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_found_count",
sqlite3_found_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_sort_count",
sqlite3_sort_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite3_max_blobsize",
sqlite3_max_blobsize, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_like_count",
sqlite3_like_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_interrupt_count",
sqlite3_interrupt_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_open_file_count",
sqlite3_open_file_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_current_time",
sqlite3_current_time, VarFlags.SQLITE3_LINK_INT );
#if SQLITE_OS_UNIX && (__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
TCL.Tcl_LinkVar(interp, "sqlite_hostid_num",
(char)&sqlite3_hostid_num, TCL.Tcl_LINK_INT);
#endif
TCL.Tcl_LinkVar( interp, "sqlite3_xferopt_count",
sqlite3_xferopt_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite3_pager_readdb_count",
sqlite3_pager_readdb_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite3_pager_writedb_count",
sqlite3_pager_writedb_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite3_pager_writej_count",
sqlite3_pager_writej_count, VarFlags.SQLITE3_LINK_INT );
#if !SQLITE_OMIT_UTF16
// TCL.Tcl_LinkVar(interp, "unaligned_string_counter",
// (char)&unaligned_string_counter, VarFlag.SQLITE3_LINK_INT);
#endif
#if !SQLITE_OMIT_UTF16
// TCL.Tcl_LinkVar(interp, "sqlite_last_needed_collation",
// (char)&pzNeededCollation, VarFlag.TCL_LINK_STRING|VarFlag.TCL_LINK_READ_ONLY);
#endif
#if SQLITE_OS_WIN
// TCL.Tcl_LinkVar(interp, "sqlite_os_type",
// (char)&sqlite3_os_type, VarFlag.SQLITE3_LINK_INT);
#endif
#if SQLITE_TEST
TCL.Tcl_LinkVar( interp, "sqlite_query_plan",
sqlite3_query_plan, VarFlags.SQLITE3_LINK_STRING | VarFlags.SQLITE3_LINK_READ_ONLY );
#endif
#if SQLITE_DEBUG
// TCL.Tcl_LinkVar(interp, "sqlite_addop_trace",
// (char)&sqlite3VdbeAddopTrace, VarFlag.SQLITE3_LINK_INT);
// TCL.Tcl_LinkVar(interp, "sqlite_where_trace",
// (char)&sqlite3WhereTrace, VarFlag.SQLITE3_LINK_INT);
// TCL.Tcl_LinkVar(interp, "sqlite_os_trace",
// (char)&sqlite3OSTrace, VarFlag.SQLITE3_LINK_INT);
#if !SQLITE_OMIT_WAL
TCL.Tcl_LinkVar((interp, "sqlite_wal_trace",
(char)&sqlite3WalTrace, VarFlag.SQLITE3_LINK_INT);
#endif
#endif
#if !SQLITE_OMIT_DISKIO
TCL.Tcl_LinkVar( interp, "sqlite_opentemp_count",
sqlite3_opentemp_count, VarFlags.SQLITE3_LINK_INT );
#endif
TCL.Tcl_LinkVar( interp, "sqlite_static_bind_value",
sqlite_static_bind_value, VarFlags.SQLITE3_LINK_STRING );
TCL.Tcl_LinkVar( interp, "sqlite_static_bind_nbyte",
sqlite_static_bind_nbyte, VarFlags.SQLITE3_LINK_INT );
// TCL.Tcl_LinkVar(interp, "sqlite_temp_directory",
// (char)&sqlite3_temp_directory, VarFlag.TCL_LINK_STRING);
TCL.Tcl_LinkVar( interp, "bitmask_size",
bitmask_size, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "sqlite_sync_count",
sqlite3_sync_count, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_fullsync_count",
sqlite3_fullsync_count, VarFlags.SQLITE3_LINK_INT );
#if (SQLITE_ENABLE_FTS3) && (SQLITE_TEST)
TCL.Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
(char)&sqlite3_fts3_enable_parentheses, TCL.Tcl_LINK_INT);
#endif
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test2_c.cs
@@ -0,0 +1,730 @@
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using DbPage = Sqlite3.PgHdr;
using Tcl_CmdProc = tcl.lang.Interp.dxObjCmdProc;
using Tcl_Interp = tcl.lang.Interp;
 
public partial class Sqlite3
{
/*
** 2001 September 15
**
** 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.
**
*************************************************************************
** Code for testing the pager.c module in SQLite. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
*************************************************************************
** 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-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
**
*************************************************************************
*/
 
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
//#include <ctype.h>
 
///*
//** Interpret an SQLite error number
//*/
//static string errorName(int rc){
// string zName;
// switch( rc ){
// case SQLITE_OK: zName = "SQLITE_OK"; break;
// case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
// case SQLITE_PERM: zName = "SQLITE_PERM"; break;
// case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
// case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
// case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
// case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
// case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
// case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
// case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
// case SQLITE_FULL: zName = "SQLITE_FULL"; break;
// case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
// case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
// case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
// case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
// case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break;
// case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break;
// case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break;
// case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break;
// default: zName = "SQLITE_Unknown"; break;
// }
// return zName;
//}
 
/*
** Page size and reserved size used for testing.
*/
static int test_pagesize = 1024;
 
/*
** Dummy page reinitializer
*/
static void pager_test_reiniter( DbPage pNotUsed )
{
return;
}
 
/*
** Usage: pager_open FILENAME N-PAGE
**
** Open a new pager
*/
//static int pager_open(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// u32 pageSize;
// Pager *pPager;
// Pgno nPage;
// int rc;
// char zBuf[100];
// if( argc!=3 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " FILENAME N-PAGE\"", 0);
// return TCL.TCL_ERROR;
// }
// if( Tcl_GetInt(interp, argv[2], nPage) ) return TCL.TCL_ERROR;
// rc = sqlite3PagerOpen(sqlite3_vfs_find(0), pPager, argv[1], 0, 0,
// SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
// pager_test_reiniter);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// sqlite3PagerSetCachesize(pPager, nPage);
// pageSize = test_pagesize;
// sqlite3PagerSetPagesize(pPager, pageSize,-1);
// sqlite3_snprintf(100, ref zBuf,"%p",pPager);
// Tcl_AppendResult(interp, zBuf);
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_close ID
**
** Close the given pager.
*/
//static int pager_close(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int rc;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// rc = sqlite3PagerClose(pPager);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_rollback ID
**
** Rollback changes
*/
//static int pager_rollback(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int rc;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// rc = sqlite3PagerRollback(pPager);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_commit ID
**
** Commit all changes
*/
//static int pager_commit(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int rc;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// rc = sqlite3PagerCommitPhaseTwo(pPager);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_stmt_begin ID
**
** Start a new checkpoint.
*/
//static int pager_stmt_begin(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int rc;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// rc = sqlite3PagerOpenSavepoint(pPager, 1);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_stmt_rollback ID
**
** Rollback changes to a checkpoint
*/
//static int pager_stmt_rollback(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int rc;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
//rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, 0);
//sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_stmt_commit ID
**
** Commit changes to a checkpoint
*/
//static int pager_stmt_commit(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int rc;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_RELEASE, 0);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_stats ID
**
** Return pager statistics.
*/
//static int pager_stats(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int i, *a;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// a = sqlite3PagerStats(pPager);
// for(i=0; i<9; i++){
// static char *zName[] = {
// "ref", "page", "max", "size", "state", "err",
// "hit", "miss", "ovfl",
// };
// char zBuf[100];
// Tcl_AppendElement(interp, zName[i]);
// sqlite3_snprintf(100, ref zBuf,"%d",a[i]);
// Tcl_AppendElement(interp, zBuf);
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_pagecount ID
**
** Return the size of the database file.
*/
//static int pager_pagecount(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// char zBuf[100];
// Pgno nPage;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// sqlite3PagerPagecount(pPager, nPage);
// sqlite3_snprintf(100, ref zBuf, "%d", nPage);
// Tcl_AppendResult(interp, zBuf);
// return TCL.TCL_OK;
//}
 
/*
** Usage: page_get ID PGNO
**
** Return a pointer to a page from the database.
*/
//static int page_get(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// char zBuf[100];
// DbPage *pPage;
// int pgno;
// int rc;
// if( argc!=3 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID PGNO\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// if( Tcl_GetInt(interp, argv[2], pgno) ) return TCL.TCL_ERROR;
//rc = sqlite3PagerSharedLock(pPager);
//if( rc==SQLITE_OK ){
// rc = sqlite3PagerGet(pPager, pgno, &pPage);
//}
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// sqlite3_snprintf(100, ref zBuf,"%p",pPage);
// Tcl_AppendResult(interp, zBuf);
// return TCL.TCL_OK;
//}
 
/*
** Usage: page_lookup ID PGNO
**
** Return a pointer to a page if the page is already in cache.
** If not in cache, return an empty string.
*/
//static int page_lookup(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// char zBuf[100];
// DbPage *pPage;
// int pgno;
// if( argc!=3 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID PGNO\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// if( Tcl_GetInt(interp, argv[2], pgno) ) return TCL.TCL_ERROR;
// pPage = sqlite3PagerLookup(pPager, pgno);
// if( pPage ){
// sqlite3_snprintf(100, ref zBuf,"%p",pPage);
// Tcl_AppendResult(interp, zBuf);
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: pager_truncate ID PGNO
*/
//static int pager_truncate(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// Pager *pPager;
// int pgno;
// if( argc!=3 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " ID PGNO\"", 0);
// return TCL.TCL_ERROR;
// }
// pPager = sqlite3TestTextToPtr(interp,argv[1].ToString());
// if( Tcl_GetInt(interp, argv[2], pgno) ) return TCL.TCL_ERROR;
// sqlite3PagerTruncateImage(pPager, pgno);
// return TCL.TCL_OK;
//}
 
 
/*
** Usage: page_unref PAGE
**
** Drop a pointer to a page.
*/
//static int page_unref(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// DbPage *pPage;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " PAGE\"", 0);
// return TCL.TCL_ERROR;
// }
// pPage = (DbPage *)sqlite3TestTextToPtr(interp,argv[1].ToString());
// sqlite3PagerUnref(pPage);
// return TCL.TCL_OK;
//}
 
/*
** Usage: page_read PAGE
**
** Return the content of a page
*/
//static int page_read(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// char zBuf[100];
// DbPage *pPage;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " PAGE\"", 0);
// return TCL.TCL_ERROR;
// }
// pPage = sqlite3TestTextToPtr(interp,argv[1].ToString());
// memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
// Tcl_AppendResult(interp, zBuf);
// return TCL.TCL_OK;
//}
 
/*
** Usage: page_number PAGE
**
** Return the page number for a page.
*/
//static int page_number(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// char zBuf[100];
// DbPage *pPage;
// if( argc!=2 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " PAGE\"", 0);
// return TCL.TCL_ERROR;
// }
// pPage = (DbPage *)sqlite3TestTextToPtr(interp,argv[1].ToString());
// sqlite3_snprintf(100, ref zBuf, "%d", sqlite3PagerPagenumber(pPage));
// Tcl_AppendResult(interp, zBuf);
// return TCL.TCL_OK;
//}
 
/*
** Usage: page_write PAGE DATA
**
** Write something into a page.
*/
//static int page_write(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// DbPage *pPage;
// char *pData;
// int rc;
// if( argc!=3 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " PAGE DATA\"", 0);
// return TCL.TCL_ERROR;
// }
// pPage = (DbPage *)sqlite3TestTextToPtr(interp,argv[1].ToString());
// rc = sqlite3PagerWrite(pPage);
// if( rc!=SQLITE_OK ){
// Tcl_AppendResult(interp, errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// pData = sqlite3PagerGetData(pPage);
// strncpy(pData, argv[2], test_pagesize-1);
// pData[test_pagesize-1] = 0;
// return TCL.TCL_OK;
//}
 
#if !SQLITE_OMIT_DISKIO
/*
** Usage: fake_big_file N FILENAME
**
** Write a few bytes at the N megabyte point of FILENAME. This will
** create a large file. If the file was a valid SQLite database, then
** the next time the database is opened, SQLite will begin allocating
** new pages after N. If N is 2096 or bigger, this will test the
** ability of SQLite to write to large files.
*/
//static int fake_big_file(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// sqlite3_vfs *pVfs;
// sqlite3_file *fd = 0;
// int rc;
// int n;
// i64 offset;
// if( argc!=3 ){
// Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
// " N-MEGABYTES FILE\"", 0);
// return TCL.TCL_ERROR;
// }
// if( Tcl_GetInt(interp, argv[1], n) ) return TCL.TCL_ERROR;
 
// pVfs = sqlite3_vfs_find(0);
// rc = sqlite3OsOpenMalloc(pVfs, argv[2], fd,
// (SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_DB), 0
// );
// if( rc !=0){
// Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// offset = n;
// offset *= 1024*1024;
// rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
// sqlite3OsCloseFree(fd);
// if( rc !=0){
// Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
// return TCL.TCL_ERROR;
// }
// return TCL.TCL_OK;
//}
#endif
 
 
/*
** test_control_pending_byte PENDING_BYTE
**
** Set the PENDING_BYTE using the sqlite3_test_control() interface.
*/
static int testPendingByte(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
int pbyte = 0;
int rc;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" PENDING-BYTE\"" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetInt( interp, argv[1], out pbyte ) )
return TCL.TCL_ERROR;
rc = sqlite3_test_control( SQLITE_TESTCTRL_PENDING_BYTE, pbyte );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return TCL.TCL_OK;
}
 
/*
** sqlite3BitvecBuiltinTest SIZE PROGRAM
**
** Invoke the SQLITE_TESTCTRL_BITVEC_TEST operator on test_control.
** See comments on sqlite3BitvecBuiltinTest() for additional information.
*/
static int testBitvecBuiltinTest(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
int sz = 0, rc;
int nProg = 0;
int[] aProg = new int[100];
string z;
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" SIZE PROGRAM\"" );
}
if ( TCL.Tcl_GetInt( interp, argv[1], out sz ) )
return TCL.TCL_ERROR;
z = argv[2].ToString() + '\0';
int iz = 0;
while ( nProg < 99 && z[iz] != 0 )
{
while ( z[iz] != 0 && !sqlite3Isdigit( z[iz] ) )
{
iz++;
}
if ( z[iz] == 0 )
break;
while ( sqlite3Isdigit( z[iz] ) )
{
aProg[nProg] = aProg[nProg] * 10 + ( z[iz] - 48 );
iz++;
}
nProg++;
}
aProg[nProg] = 0;
rc = sqlite3_test_control( SQLITE_TESTCTRL_BITVEC_TEST, sz, aProg );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return TCL.TCL_OK;
}
 
/*
** Register commands with the TCL interpreter.
*/
static Var.SQLITE3_GETSET TCLsqlite3PendingByte = new Var.SQLITE3_GETSET( "sqlite_pending_byte" );
 
 
public static int Sqlitetest2_Init( Tcl_Interp interp )
{
//extern int sqlite3_io_error_persist;
//extern int sqlite3_io_error_pending;
//extern int sqlite3_io_error_hit;
//extern int sqlite3_io_error_hardhit;
//extern int sqlite3_diskfull_pending;
//extern int sqlite3_diskfull;
//extern int sqlite3_pager_n_sort_bucket;
//static struct {
// char *zName;
// Tcl_CmdProc *xProc;
//} aCmd[] = {
_aCmd[] aCmd = new _aCmd[] {
//new _aCmd( "pager_open", (Tcl_CmdProc)pager_open ),
//new _aCmd( "pager_close", (Tcl_CmdProc)pager_close ),
// { "pager_commit", (Tcl_CmdProc*)pager_commit },
// { "pager_rollback", (Tcl_CmdProc*)pager_rollback },
// { "pager_stmt_begin", (Tcl_CmdProc*)pager_stmt_begin },
// { "pager_stmt_commit", (Tcl_CmdProc*)pager_stmt_commit },
// { "pager_stmt_rollback", (Tcl_CmdProc*)pager_stmt_rollback },
// { "pager_stats", (Tcl_CmdProc*)pager_stats },
// { "pager_pagecount", (Tcl_CmdProc*)pager_pagecount },
// { "page_get", (Tcl_CmdProc*)page_get },
// { "page_lookup", (Tcl_CmdProc*)page_lookup },
// { "page_unref", (Tcl_CmdProc*)page_unref },
// { "page_read", (Tcl_CmdProc*)page_read },
// { "page_write", (Tcl_CmdProc*)page_write },
// { "page_number", (Tcl_CmdProc*)page_number },
// { "pager_truncate", (Tcl_CmdProc*)pager_truncate },
#if !SQLITE_OMIT_DISKIO
// { "fake_big_file", (Tcl_CmdProc*)fake_big_file },
#endif
new _aCmd( "sqlite3BitvecBuiltinTest",(Tcl_CmdProc)testBitvecBuiltinTest),
new _aCmd( "sqlite3_test_control_pending_byte",(Tcl_CmdProc)testPendingByte),
};
int i;
for ( i = 0; i < aCmd.Length; i++ )
{//sizeof(aCmd)/sizeof(aCmd[0]); i++){
TCL.Tcl_CreateCommand( interp, aCmd[i].zName, aCmd[i].xProc, null, null );
}
 
TCL.Tcl_LinkVar( interp, "sqlite_io_error_pending",
sqlite3_io_error_pending, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_io_error_persist",
sqlite3_io_error_persist, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_io_error_hit",
sqlite3_io_error_hit, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_io_error_hardhit",
sqlite3_io_error_hardhit, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_diskfull_pending",
sqlite3_diskfull_pending, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "sqlite_diskfull",
sqlite3_diskfull, VarFlags.SQLITE3_LINK_INT );
#if !SQLITE_OMIT_WSD
TCL.Tcl_LinkVar( interp, "sqlite_pending_byte",
TCLsqlite3PendingByte, VarFlags.SQLITE3_LINK_INT );
#endif
TCLsqlite3PendingByte.iValue = sqlite3PendingByte;
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test3_c.cs
@@ -0,0 +1,802 @@
using System.Diagnostics;
 
using i64 = System.Int64;
using u32 = System.UInt32;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using Tcl_CmdProc = tcl.lang.Interp.dxObjCmdProc;
using Tcl_Interp = tcl.lang.Interp;
using System.Text;
 
public partial class Sqlite3
{
/*
** 2001 September 15
**
** 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.
**
*************************************************************************
** Code for testing the btree.c module in SQLite. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
//#include "sqliteInt.h"
//#include "btreeInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
 
/*
** Interpret an SQLite error number
*/
static string errorName( int rc )
{
string zName;
switch ( rc )
{
case SQLITE_OK:
zName = "SQLITE_OK";
break;
case SQLITE_ERROR:
zName = "SQLITE_ERROR";
break;
case SQLITE_PERM:
zName = "SQLITE_PERM";
break;
case SQLITE_ABORT:
zName = "SQLITE_ABORT";
break;
case SQLITE_BUSY:
zName = "SQLITE_BUSY";
break;
case SQLITE_NOMEM:
zName = "SQLITE_NOMEM";
break;
case SQLITE_READONLY:
zName = "SQLITE_READONLY";
break;
case SQLITE_INTERRUPT:
zName = "SQLITE_INTERRUPT";
break;
case SQLITE_IOERR:
zName = "SQLITE_IOERR";
break;
case SQLITE_CORRUPT:
zName = "SQLITE_CORRUPT";
break;
case SQLITE_FULL:
zName = "SQLITE_FULL";
break;
case SQLITE_CANTOPEN:
zName = "SQLITE_CANTOPEN";
break;
case SQLITE_PROTOCOL:
zName = "SQLITE_PROTOCOL";
break;
case SQLITE_EMPTY:
zName = "SQLITE_EMPTY";
break;
case SQLITE_LOCKED:
zName = "SQLITE_LOCKED";
break;
default:
zName = "SQLITE_Unknown";
break;
}
return zName;
}
 
/*
** A bogus sqlite3 connection structure for use in the btree
** tests.
*/
static sqlite3 sDb = new sqlite3();
static int nRefSqlite3 = 0;
 
/*
** Usage: btree_open FILENAME NCACHE
**
** Open a new database
*/
static int btree_open(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
Btree pBt = null;
int rc;
int nCache = 0;
StringBuilder zBuf = new StringBuilder( 100 );
if ( argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" FILENAME NCACHE\"", "" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetInt( interp, argv[2], out nCache ) )
return TCL.TCL_ERROR;
nRefSqlite3++;
if ( nRefSqlite3 == 1 )
{
sDb.pVfs = sqlite3_vfs_find( null );
sDb.mutex = sqlite3MutexAlloc( SQLITE_MUTEX_RECURSIVE );
sqlite3_mutex_enter( sDb.mutex );
}
rc = sqlite3BtreeOpen( sDb.pVfs, argv[1].ToString(), sDb, ref pBt, 0,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB );
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, errorName( rc ), null );
return TCL.TCL_ERROR;
}
sqlite3BtreeSetCacheSize( pBt, nCache );
sqlite3_snprintf( 100, zBuf, "->%p", pBt );
if ( TCL.Tcl_CreateCommandPointer( interp, zBuf, pBt ) )
{
return TCL.TCL_ERROR;
}
else
TCL.Tcl_AppendResult( interp, zBuf, null );
return TCL.TCL_OK;
}
 
/*
** Usage: btree_close ID
**
** Close the given database.
*/
static int btree_close(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
Btree pBt;
int rc;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID\"", null );
return TCL.TCL_ERROR;
}
pBt = (Btree)sqlite3TestTextToPtr( interp, argv[1].ToString() );
rc = sqlite3BtreeClose( ref pBt );
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, errorName( rc ), null );
return TCL.TCL_ERROR;
}
nRefSqlite3--;
if ( nRefSqlite3 == 0 )
{
sqlite3_mutex_leave( sDb.mutex );
sqlite3_mutex_free( sDb.mutex );
sDb.mutex = null;
sDb.pVfs = null;
}
return TCL.TCL_OK;
}
 
 
/*
** Usage: btree_begin_transaction ID
**
** Start a new transaction
*/
static int btree_begin_transaction(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
Btree pBt;
int rc;
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID\"", null );
return TCL.TCL_ERROR;
}
pBt = (Btree)sqlite3TestTextToPtr( interp, argv[1].ToString() );
sqlite3BtreeEnter( pBt );
rc = sqlite3BtreeBeginTrans( pBt, 1 );
sqlite3BtreeLeave( pBt );
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, errorName( rc ), null );
;
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
/*
** Usage: btree_pager_stats ID
**
** Returns pager statistics
*/
static int btree_pager_stats(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
Btree pBt;
int i;
int[] a;
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID\"" );
return TCL.TCL_ERROR;
}
pBt = (Btree)sqlite3TestTextToPtr( interp, argv[1].ToString() );
 
/* Normally in this file, with a b-tree handle opened using the
** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
** But this function is sometimes called with a btree handle obtained
** from an open SQLite connection (using [btree_from_db]). In this case
** we need to obtain the mutex for the controlling SQLite handle before
** it is safe to call sqlite3BtreeEnter().
*/
sqlite3_mutex_enter( pBt.db.mutex );
 
sqlite3BtreeEnter( pBt );
a = sqlite3PagerStats( sqlite3BtreePager( pBt ) );
for ( i = 0; i < 11; i++ )
{
string[] zName = new string[]{
"ref", "page", "max", "size", "state", "err",
"hit", "miss", "ovfl", "read", "write"
};
StringBuilder zBuf = new StringBuilder( 100 );
TCL.Tcl_AppendElement( interp, zName[i] );
sqlite3_snprintf( 100, zBuf, "%d", a[i] );
TCL.Tcl_AppendElement( interp, zBuf );
}
sqlite3BtreeLeave( pBt );
/* Release the mutex on the SQLite handle that controls this b-tree */
sqlite3_mutex_leave( pBt.db.mutex );
return TCL.TCL_OK;
}
 
/*
** Usage: btree_cursor ID TABLENUM WRITEABLE
**
** Create a new cursor. Return the ID for the cursor.
*/
static int btree_cursor(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
Btree pBt;
int iTable = 0;
BtCursor pCur;
int rc = SQLITE_OK;
int wrFlag = 0;
StringBuilder zBuf = new StringBuilder( 30 );
 
if ( argc != 4 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID TABLENUM WRITEABLE\"" );
return TCL.TCL_ERROR;
}
pBt = (Btree)sqlite3TestTextToPtr( interp, argv[1].ToString() );
if ( TCL.Tcl_GetInt( interp, argv[2], out iTable ) )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetBoolean( interp, argv[3], out wrFlag ) )
return TCL.TCL_ERROR;
//pCur = (BtCursor )ckalloc(sqlite3BtreeCursorSize());
pCur = new BtCursor();// memset( pCur, 0, sqlite3BtreeCursorSize() );
sqlite3BtreeEnter( pBt );
#if !SQLITE_OMIT_SHARED_CACHE
rc = sqlite3BtreeLockTable( pBt, iTable, wrFlag );
#endif
if ( rc == SQLITE_OK )
{
rc = sqlite3BtreeCursor( pBt, iTable, wrFlag, null, pCur );
}
sqlite3BtreeLeave( pBt );
if ( rc != 0 )
{
pCur = null;// ckfree( pCur );
TCL.Tcl_AppendResult( interp, errorName( rc ), null );
;
return TCL.TCL_ERROR;
}
sqlite3_snprintf( 30, zBuf, "->%p", pCur );
if ( TCL.Tcl_CreateCommandPointer( interp, zBuf, pCur ) )
{
return TCL.TCL_ERROR;
}
else
TCL.Tcl_AppendResult( interp, zBuf );
return SQLITE_OK;
}
 
/*
** Usage: btree_close_cursor ID
**
** Close a cursor opened using btree_cursor.
*/
static int btree_close_cursor(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
BtCursor pCur;
Btree pBt;
int rc;
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID\"" );
return TCL.TCL_ERROR;
}
pCur = (BtCursor)sqlite3TestTextToPtr( interp, argv[1].ToString() );
pBt = pCur.pBtree;
sqlite3BtreeEnter( pBt );
rc = sqlite3BtreeCloseCursor( pCur );
sqlite3BtreeLeave( pBt );
pCur = null;//ckfree( (char*)pCur );
if ( rc != 0 )
{
TCL.Tcl_AppendResult( interp, errorName( rc ), null );
;
return TCL.TCL_ERROR;
}
return SQLITE_OK;
}
 
/*
** Usage: btree_next ID
**
** Move the cursor to the next entry in the table. Return 0 on success
** or 1 if the cursor was already on the last entry in the table or if
** the table is empty.
*/
static int btree_next(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
BtCursor pCur;
int rc;
int res = 0;
StringBuilder zBuf = new StringBuilder( 100 );
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID\"" );
return TCL.TCL_ERROR;
}
pCur = (BtCursor)sqlite3TestTextToPtr( interp, argv[1].ToString() );
#if SQLITE_TEST
sqlite3BtreeEnter( pCur.pBtree );
#endif
rc = sqlite3BtreeNext( pCur, ref res );
#if SQLITE_TEST
sqlite3BtreeLeave( pCur.pBtree );
#endif
if ( rc != 0 )
{
TCL.Tcl_AppendResult( interp, errorName( rc ), null );
;
return TCL.TCL_ERROR;
}
sqlite3_snprintf( 100, zBuf, "%d", res );
TCL.Tcl_AppendResult( interp, zBuf );
return SQLITE_OK;
}
 
/*
** Usage: btree_first ID
**
** Move the cursor to the first entry in the table. Return 0 if the
** cursor was left point to something and 1 if the table is empty.
*/
static int btree_first(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
BtCursor pCur;
int rc;
int res = 0;
StringBuilder zBuf = new StringBuilder( 100 );
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID\"" );
return TCL.TCL_ERROR;
}
pCur = (BtCursor)sqlite3TestTextToPtr( interp, argv[1].ToString() );
#if SQLITE_TEST
sqlite3BtreeEnter( pCur.pBtree );
#endif
rc = sqlite3BtreeFirst( pCur, ref res );
#if SQLITE_TEST
sqlite3BtreeLeave( pCur.pBtree );
#endif
if ( rc != 0 )
{
TCL.Tcl_AppendResult( interp, errorName( rc ), null );
;
return TCL.TCL_ERROR;
}
sqlite3_snprintf( 100, zBuf, "%d", res );
TCL.Tcl_AppendResult( interp, zBuf );
return SQLITE_OK;
}
 
/*
** Usage: btree_eof ID
**
** Return TRUE if the given cursor is not pointing at a valid entry.
** Return FALSE if the cursor does point to a valid entry.
*/
//static int btree_eof(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// BtCursor pCur;
// int rc;
// char zBuf[50];
 
// if( argc!=2 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0].ToString(),
// " ID\"");
// return TCL.TCL_ERROR;
// }
// pCur = (BtCursor)sqlite3TestTextToPtr(interp,argv[1].ToString());
// sqlite3BtreeEnter(pCur.pBtree);
// rc = sqlite3BtreeEof(pCur);
// sqlite3BtreeLeave(pCur.pBtree);
// sqlite3_snprintf(100, ref zBuf, "%d", rc);
// TCL.Tcl_AppendResult(interp, zBuf);
// return SQLITE_OK;
//}
 
/*
** Usage: btree_payload_size ID
**
** Return the number of bytes of payload
*/
static int btree_payload_size(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
BtCursor pCur;
i64 n1 = 0;
u32 n2 = 0;
StringBuilder zBuf = new StringBuilder( 50 );
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" ID\"" );
return TCL.TCL_ERROR;
}
pCur = (BtCursor)sqlite3TestTextToPtr( interp, argv[1].ToString() );
#if SQLITE_TEST
sqlite3BtreeEnter( pCur.pBtree );
#endif
 
/* The cursor may be in "require-seek" state. If this is the case, the
** call to BtreeDataSize() will fix it. */
sqlite3BtreeDataSize( pCur, ref n2 );
if ( pCur.apPage[pCur.iPage].intKey != 0 )
{
n1 = 0;
}
else
{
sqlite3BtreeKeySize( pCur, ref n1 );
}
sqlite3BtreeLeave( pCur.pBtree );
sqlite3_snprintf( 30, zBuf, "%d", (int)( n1 + n2 ) );
TCL.Tcl_AppendResult( interp, zBuf );
return SQLITE_OK;
}
 
/*
** usage: varint_test START MULTIPLIER COUNT INCREMENT
**
** This command tests the putVarint() and getVarint()
** routines, both for accuracy and for speed.
**
** An integer is written using putVarint() and read back with
** getVarint() and varified to be unchanged. This repeats COUNT
** times. The first integer is START*MULTIPLIER. Each iteration
** increases the integer by INCREMENT.
**
** This command returns nothing if it works. It returns an error message
** if something goes wrong.
*/
static int btree_varint_test(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that _invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
int start = 0, mult = 0, count = 0, incr = 0;
int _in;
u32 _out = 0;
int n1, n2, i, j;
byte[] zBuf = new byte[100];
if ( argc != 5 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" START MULTIPLIER COUNT incrEMENT\"", 0 );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetInt( interp, argv[1], out start ) )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetInt( interp, argv[2], out mult ) )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetInt( interp, argv[3], out count ) )
return TCL.TCL_ERROR;
if ( TCL.Tcl_GetInt( interp, argv[4], out incr ) )
return TCL.TCL_ERROR;
_in = start;
_in *= mult;
for ( i = 0; i < count; i++ )
{
StringBuilder zErr = new StringBuilder( 200 );
n1 = putVarint( zBuf, 0, _in );
if ( n1 > 9 || n1 < 1 )
{
sqlite3_snprintf( 100, zErr, "putVarint returned %d - should be between 1 and 9", n1 );
TCL.Tcl_AppendResult( interp, zErr );
return TCL.TCL_ERROR;
}
n2 = getVarint( zBuf, 0, out _out );
if ( n1 != n2 )
{
sqlite3_snprintf( 100, zErr, "putVarint returned %d and GetVar_int returned %d", n1, n2 );
TCL.Tcl_AppendResult( interp, zErr );
return TCL.TCL_ERROR;
}
if ( _in != (int)_out )
{
sqlite3_snprintf( 100, zErr, "Wrote 0x%016llx and got back 0x%016llx", _in, _out );
TCL.Tcl_AppendResult( interp, zErr );
return TCL.TCL_ERROR;
}
if ( ( _in & 0xffffffff ) == _in )
{
u32 _out32 = 0;
n2 = getVarint32( zBuf, out _out32 );
_out = _out32;
if ( n1 != n2 )
{
sqlite3_snprintf( 100, zErr, "putVarint returned %d and GetVar_int32 returned %d",
n1, n2 );
TCL.Tcl_AppendResult( interp, zErr );
return TCL.TCL_ERROR;
}
if ( _in != (int)_out )
{
sqlite3_snprintf( 100, zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVar_int32",
_in, _out );
TCL.Tcl_AppendResult( interp, zErr );
return TCL.TCL_ERROR;
}
}
 
/* _in order to get realistic tim_ings, run getVar_int 19 more times.
** This is because getVar_int is called ab_out 20 times more often
** than putVarint.
*/
for ( j = 0; j < 19; j++ )
{
getVarint( zBuf, 0, out _out );
}
_in += incr;
}
return TCL.TCL_OK;
}
 
/*
** usage: btree_from_db DB-HANDLE
**
** This command returns the btree handle for the main database associated
** with the database-handle passed as the argument. Example usage:
**
** sqlite3 db test.db
** set bt [btree_from_db db]
*/
static int btree_from_db(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
StringBuilder zBuf = new StringBuilder( 100 );
WrappedCommand info = null;
sqlite3 db;
Btree pBt;
int iDb = 0;
 
if ( argc != 2 && argc != 3 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0].ToString(),
" DB-HANDLE ?N?\"" );
return TCL.TCL_ERROR;
}
 
if ( TCL.Tcl_GetCommandInfo( interp, argv[1].ToString(), out info ) )
{
TCL.Tcl_AppendResult( interp, "No such db-handle: \"", argv[1], "\"" );
return TCL.TCL_ERROR;
}
if ( argc == 3 )
{
iDb = atoi( argv[2].ToString() );
}
 
db = ( (SqliteDb)info.objClientData ).db;
Debug.Assert( db != null );
 
pBt = db.aDb[iDb].pBt;
sqlite3_snprintf( 50, zBuf, "->%p", pBt );
if ( TCL.Tcl_CreateCommandPointer( interp, zBuf, pBt ) )
{
return TCL.TCL_ERROR;
}
else
TCL.Tcl_SetResult( interp, zBuf, TCL.TCL_VOLATILE );
return TCL.TCL_OK;
}
 
 
/*
** Usage: btree_ismemdb ID
**
** Return true if the B-Tree is in-memory.
*/
static int btree_ismemdb(
object NotUsed,
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int argc, /* Number of arguments */
TclObject[] argv /* Text of each argument */
)
{
Btree pBt;
int res;
 
if ( argc != 2 )
{
TCL.Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0],
" ID\"" );
return TCL.TCL_ERROR;
}
pBt = (Btree)sqlite3TestTextToPtr( interp, argv[1].ToString() );
sqlite3_mutex_enter( pBt.db.mutex );
sqlite3BtreeEnter( pBt );
res = sqlite3PagerIsMemdb( sqlite3BtreePager( pBt ) ) ? 1 : 0;
sqlite3BtreeLeave( pBt );
sqlite3_mutex_leave( pBt.db.mutex );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewBooleanObj( res ) );
return TCL.TCL_OK;
}
 
/*
** usage: btree_set_cache_size ID NCACHE
**
** Set the size of the cache used by btree $ID.
*/
//static int btree_set_cache_size(
// object NotUsed,
// Tcl_Interp interp, /* The TCL interpreter that invoked this command */
// int argc, /* Number of arguments */
// TclObject[] argv /* Text of each argument */
//){
// int nCache;
// Btree pBt;
 
// if( argc!=3 ){
// TCL.Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0].ToString(),
// " BT NCACHE\"");
// return TCL.TCL_ERROR;
// }
// pBt = (Btree)sqlite3TestTextToPtr(interp,argv[1].ToString());
// if(TCL.Tcl_GetInt(interp, argv[2], nCache) ) return TCL.TCL_ERROR;
 
// sqlite3_mutex_enter(pBt.db.mutex);
// sqlite3BtreeEnter(pBt);
// sqlite3BtreeSetCacheSize(pBt, nCache);
// sqlite3BtreeLeave(pBt);
// sqlite3_mutex_leave(pBt.db.mutex);
 
// return TCL.TCL_OK;
//}
 
 
/*
** Register commands with the TCL interpreter.
*/
public class _aCmd
{
public string zName;
public Tcl_CmdProc xProc;
 
public _aCmd( string zName, Tcl_CmdProc xProc )
{
this.zName = zName;
this.xProc = xProc;
}
}
 
 
public static int Sqlitetest3_Init( Tcl_Interp interp )
{
_aCmd[] aCmd = new _aCmd[] {
new _aCmd( "btree_open", (Tcl_CmdProc)btree_open ),
new _aCmd( "btree_close", (Tcl_CmdProc)btree_close ),
new _aCmd( "btree_begin_transaction", (Tcl_CmdProc)btree_begin_transaction ),
new _aCmd( "btree_pager_stats", (Tcl_CmdProc)btree_pager_stats ),
new _aCmd( "btree_cursor", (Tcl_CmdProc)btree_cursor ),
new _aCmd( "btree_close_cursor", (Tcl_CmdProc)btree_close_cursor ),
new _aCmd( "btree_next", (Tcl_CmdProc)btree_next ),
//new _aCmd( "btree_eof", (Tcl_CmdProc)btree_eof ),
new _aCmd( "btree_payload_size", (Tcl_CmdProc)btree_payload_size ),
new _aCmd( "btree_first", (Tcl_CmdProc)btree_first ),
new _aCmd( "btree_varint_test", (Tcl_CmdProc)btree_varint_test ),
new _aCmd( "btree_from_db", (Tcl_CmdProc)btree_from_db ),
new _aCmd( "btree_ismemdb", (Tcl_CmdProc)btree_ismemdb ),
//new _aCmd( "btree_set_cache_size", (Tcl_CmdProc)btree_set_cache_size ),
};
int i;
 
for ( i = 0; i < aCmd.Length; i++ )
{ //sizeof(aCmd)/sizeof(aCmd[0]); i++){
TCL.Tcl_CreateCommand( interp, aCmd[i].zName, aCmd[i].xProc, null, null );
}
 
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test8_c.cs
@@ -0,0 +1,1579 @@
using System;
using System.Diagnostics;
using System.Text;
 
using sqlite_int64 = System.Int64;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_CmdInfo = tcl.lang.WrappedCommand;
using Tcl_DString = tcl.lang.TclString;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
 
 
public partial class Sqlite3
{
/*
** 2006 June 10
**
** 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.
**
*************************************************************************
** Code for testing the virtual table interfaces. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
 
#if !SQLITE_OMIT_VIRTUALTABLE
 
//typedef struct echo_vtab echo_vtab;
//typedef struct echo_cursor echo_cursor;
 
/*
** The test module defined in this file uses four global Tcl variables to
** commicate with test-scripts:
**
** $::echo_module
** $::echo_module_sync_fail
** $::echo_module_begin_fail
** $::echo_module_cost
**
** The variable ::echo_module is a list. Each time one of the following
** methods is called, one or more elements are appended to the list.
** This is used for automated testing of virtual table modules.
**
** The ::echo_module_sync_fail variable is set by test scripts and read
** by code in this file. If it is set to the name of a real table in the
** the database, then all xSync operations on echo virtual tables that
** use the named table as a backing store will fail.
*/
 
/*
** Errors can be provoked within the following echo virtual table methods:
**
** xBestIndex xOpen xFilter xNext
** xColumn xRowid xUpdate xSync
** xBegin xRename
**
** This is done by setting the global tcl variable:
**
** echo_module_fail($method,$tbl)
**
** where $method is set to the name of the virtual table method to fail
** (i.e. "xBestIndex") and $tbl is the name of the table being echoed (not
** the name of the virtual table, the name of the underlying real table).
*/
 
/*
** An echo virtual-table object.
**
** echo.vtab.aIndex is an array of booleans. The nth entry is true if
** the nth column of the real table is the left-most column of an index
** (implicit or otherwise). In other words, if SQLite can optimize
** a query like "SELECT * FROM real_table WHERE col = ?".
**
** Member variable aCol[] contains copies of the column names of the real
** table.
*/
class echo_vtab : sqlite3_vtab
{
//public sqlite3_vtab base;
public Tcl_Interp interp; /* Tcl interpreter containing debug variables */
public sqlite3 db; /* Database connection */
 
public int isPattern;
public int inTransaction; /* True if within a transaction */
public string zThis; /* Name of the echo table */
public string zTableName; /* Name of the real table */
public string zLogName; /* Name of the log table */
public int nCol; /* Number of columns in the real table */
public int[] aIndex; /* Array of size nCol. True if column has an index */
public string[] aCol; /* Array of size nCol. Column names */
};
 
/* An echo cursor object */
class echo_cursor : sqlite3_vtab_cursor
{
//public sqlite3_vtab_cursor base;
public sqlite3_stmt pStmt;
};
 
static int simulateVtabError( echo_vtab p, string zMethod )
{
string zErr;
StringBuilder zVarname = new StringBuilder( 128 );
//zVarname[127] = '\0';
sqlite3_snprintf( 127, zVarname, "echo_module_fail(%s,%s)", zMethod, p.zTableName );
zErr = TCL.Tcl_GetVar( p.interp, zVarname.ToString(), (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY ).ToString();
if ( zErr != "" )
{
p.zErrMsg = sqlite3_mprintf( "echo-vtab-error: %s", zErr );
}
return ( zErr != "" ? 1 : 0 );
}
 
/*
** Convert an SQL-style quoted string into a normal string by removing
** the quote characters. The conversion is done in-place. If the
** input does not begin with a quote character, then this routine
** is a no-op.
**
** Examples:
**
** "abc" becomes abc
** 'xyz' becomes xyz
** [pqr] becomes pqr
** `mno` becomes mno
*/
static void dequoteString( ref string z )
{
//int quote;
//int i, j;
if ( String.IsNullOrEmpty( z ) )
return;
sqlite3Dequote( ref z );
//quote = z[0];
//switch( quote ){
// case '\'': break;
// case '"': break;
// case '`': break; /* For MySQL compatibility */
// case '[': quote = ']'; break; /* For MS SqlServer compatibility */
// default: return;
//}
//for(i=1, j=0; z[i]; i++){
// if( z[i]==quote ){
// if( z[i+1]==quote ){
// z[j++] = quote;
// i++;
// }else{
// z[j++] = 0;
// break;
// }
// }else{
// z[j++] = z[i];
// }
//}
}
 
/*
** Retrieve the column names for the table named zTab via database
** connection db. SQLITE_OK is returned on success, or an sqlite error
** code otherwise.
**
** If successful, the number of columns is written to pnCol. paCol is
** set to point at sqlite3_malloc()'d space containing the array of
** nCol column names. The caller is responsible for calling sqlite3_free
** on paCol.
*/
static int getColumnNames(
sqlite3 db,
string zTab,
out string[] paCol,
out int pnCol
)
{
string[] aCol = null;
string zSql;
sqlite3_stmt pStmt = null;
int rc = SQLITE_OK;
int nCol = 0;
 
/* Prepare the statement "SELECT * FROM <tbl>". The column names
** of the result set of the compiled SELECT will be the same as
** the column names of table <tbl>.
*/
zSql = sqlite3_mprintf( "SELECT * FROM %Q", zTab );
//if( null==zSql ){
// rc = SQLITE_NOMEM;
// goto _out;
//}
rc = sqlite3_prepare( db, zSql, -1, ref pStmt, 0 );
//sqlite3_free(zSql);
 
if ( rc == SQLITE_OK )
{
int ii;
int nBytes;
string zSpace;
nCol = sqlite3_column_count( pStmt );
 
/* Figure out how much space to allocate for the array of column names
** (including space for the strings themselves). Then allocate it.
*/
nBytes = sizeof( char ) * nCol;
for ( ii = 0; ii < nCol; ii++ )
{
string zName = sqlite3_column_name( pStmt, ii );
//if( null==zName ){
// rc = SQLITE_NOMEM;
// goto _out;
//}
nBytes += zName.Length + 1;//strlen( zName ) + 1;
}
aCol = new string[nCol];//(char )sqlite3MallocZero(nBytes);
//if( null==aCol ){
// rc = SQLITE_NOMEM;
// goto out_;
//}
 
/* Copy the column names into the allocated space and set up the
** pointers in the aCol[] array.
*/
//zSpace = (char)( &aCol[nCol] );
for ( ii = 0; ii < nCol; ii++ )
{
//aCol[ii] = zSpace;
//zSpace += sprintf( zSpace, "%s", sqlite3_column_name( pStmt, ii ) );
//zSpace++;
aCol[ii] = sqlite3_column_name( pStmt, ii );
}
//Debug.Assert( (zSpace-nBytes)==(char )aCol );
}
 
paCol = aCol;
pnCol = nCol;
 
//_out:
sqlite3_finalize( pStmt );
return rc;
}
 
/*
** Parameter zTab is the name of a table in database db with nCol
** columns. This function allocates an array of integers nCol in
** size and populates it according to any implicit or explicit
** indices on table zTab.
**
** If successful, SQLITE_OK is returned and paIndex set to point
** at the allocated array. Otherwise, an error code is returned.
**
** See comments associated with the member variable aIndex above
** "struct echo_vtab" for details of the contents of the array.
*/
static int getIndexArray(
sqlite3 db, /* Database connection */
string zTab, /* Name of table in database db */
int nCol,
ref int[] paIndex
)
{
sqlite3_stmt pStmt = null;
int[] aIndex = null;
int rc = 0;
string zSql;
 
/* Allocate space for the index array */
aIndex = new int[nCol];//(int )sqlite3MallocZero(sizeof(int) * nCol);
// if( null==aIndex ){
// rc = SQLITE_NOMEM;
// goto get_index_array_out;
// }
 
/* Compile an sqlite pragma to loop through all indices on table zTab */
zSql = sqlite3_mprintf( "PRAGMA index_list(%s)", zTab );
// if( null==zSql ){
// rc = SQLITE_NOMEM;
// goto get_index_array_out;
// }
rc = sqlite3_prepare( db, zSql, -1, ref pStmt, 0 );
// //sqlite3_free(zSql);
 
/* For each index, figure out the left-most column and set the
** corresponding entry in aIndex[] to 1.
*/
while ( pStmt != null && sqlite3_step( pStmt ) == SQLITE_ROW )
{
string zIdx = (string)sqlite3_column_text( pStmt, 1 );
sqlite3_stmt pStmt2 = null;
zSql = sqlite3_mprintf( "PRAGMA index_info(%s)", zIdx );
//if ( null == zSql )
//{
// rc = SQLITE_NOMEM;
// goto get_index_array_out;
//}
rc = sqlite3_prepare( db, zSql, -1, ref pStmt2, 0 );
//sqlite3_free(zSql);
if ( pStmt2 != null && sqlite3_step( pStmt2 ) == SQLITE_ROW )
{
int cid = sqlite3_column_int( pStmt2, 1 );
Debug.Assert( cid >= 0 && cid < nCol );
aIndex[cid] = 1;
}
if ( pStmt2 != null )
{
rc = sqlite3_finalize( pStmt2 );
}
if ( rc != SQLITE_OK )
{
goto get_index_array_out;
}
}
 
 
get_index_array_out:
if ( pStmt != null )
{
int rc2 = sqlite3_finalize( pStmt );
if ( rc == SQLITE_OK )
{
rc = rc2;
}
}
if ( rc != SQLITE_OK )
{
//sqlite3_free(aIndex);
aIndex = null;
}
paIndex = aIndex;
return rc;
}
 
/*
** Global Tcl variable $echo_module is a list. This routine appends
** the string element zArg to that list in interpreter interp.
*/
static void appendToEchoModule( Tcl_Interp interp, string zArg )
{
int flags = ( TCL.TCL_APPEND_VALUE | TCL.TCL_LIST_ELEMENT | TCL.TCL_GLOBAL_ONLY );
TCL.Tcl_SetVar( interp, "echo_module", ( zArg != null ? zArg : "" ), flags );
}
 
/*
** This function is called from within the echo-modules xCreate and
** xConnect methods. The argc and argv arguments are copies of those
** passed to the calling method. This function is responsible for
** calling sqlite3_declare_vtab() to declare the schema of the virtual
** table being created or connected.
**
** If the constructor was passed just one argument, i.e.:
**
** CREATE TABLE t1 AS echo(t2);
**
** Then t2 is assumed to be the name of a *real* database table. The
** schema of the virtual table is declared by passing a copy of the
** CREATE TABLE statement for the real table to sqlite3_declare_vtab().
** Hence, the virtual table should have exactly the same column names and
** types as the real table.
*/
static int echoDeclareVtab(
echo_vtab pVtab,
sqlite3 db
)
{
int rc = SQLITE_OK;
 
if ( pVtab.zTableName != null )
{
sqlite3_stmt pStmt = null;
rc = sqlite3_prepare( db,
"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ?",
-1, ref pStmt, 0 );
if ( rc == SQLITE_OK )
{
sqlite3_bind_text( pStmt, 1, pVtab.zTableName, -1, null );
if ( sqlite3_step( pStmt ) == SQLITE_ROW )
{
int rc2;
string zCreateTable = (string)sqlite3_column_text( pStmt, 0 );
rc = sqlite3_declare_vtab( db, zCreateTable );
rc2 = sqlite3_finalize( pStmt );
if ( rc == SQLITE_OK )
{
rc = rc2;
}
}
else
{
rc = sqlite3_finalize( pStmt );
if ( rc == SQLITE_OK )
{
rc = SQLITE_ERROR;
}
}
if ( rc == SQLITE_OK )
{
rc = getColumnNames( db, pVtab.zTableName, out pVtab.aCol, out pVtab.nCol );
}
if ( rc == SQLITE_OK )
{
rc = getIndexArray( db, pVtab.zTableName, pVtab.nCol, ref pVtab.aIndex );
}
}
}
 
return rc;
}
 
/*
** This function frees all runtime structures associated with the virtual
** table pVtab.
*/
static int echoDestructor( ref object pVtab )
{
//echo_vtab p = (echo_vtab)pVtab;
//sqlite3_free(p.aIndex);
//sqlite3_free(p.aCol);
//sqlite3_free(p.zThis);
//sqlite3_free(p.zTableName);
//sqlite3_free(p.zLogName);
//sqlite3_free(p);
pVtab = null;
return 0;
}
 
//typedef struct EchoModule EchoModule;
class EchoModule : sqlite3_vtab
{
public Tcl_Interp interp;
};
 
/*
** This function is called to do the work of the xConnect() method -
** to allocate the required in-memory structures for a newly connected
** virtual table.
*/
static int echoConstructor(
sqlite3 db,
object pAux,
int argc, string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
)
{
int rc;
int i;
echo_vtab pVtab;
pzErr = "";
 
/* Allocate the sqlite3_vtab/echo_vtab structure itself */
pVtab = new echo_vtab();//sqlite3MallocZero( sizeof(*pVtab) );
//if( null==pVtab ){
// return SQLITE_NOMEM;
//}
pVtab.interp = ( (EchoModule)pAux ).interp;
pVtab.db = db;
 
/* Allocate echo_vtab.zThis */
pVtab.zThis = sqlite3_mprintf( "%s", argv[2] );
//if( null==pVtab.zThis ){
// object obj = ppVtab;
// echoDestructor( ref obj );
// obj = null;
// return SQLITE_NOMEM;
//}
 
/* Allocate echo_vtab.zTableName */
if ( argc > 3 )
{
pVtab.zTableName = sqlite3_mprintf( "%s", argv[3] );
dequoteString( ref pVtab.zTableName );
if ( !String.IsNullOrEmpty( pVtab.zTableName ) && pVtab.zTableName[0] == '*' )
{
string z = sqlite3_mprintf( "%s%s", argv[2], ( pVtab.zTableName.Substring(1) ) );
//sqlite3_free(pVtab.zTableName);
pVtab.zTableName = z;
pVtab.isPattern = 1;
}
//if( null==pVtab.zTableName ){
// object obj = ppVtab;
// echoDestructor( ref obj );
// obj = null;
// return SQLITE_NOMEM;
//}
}
 
/* Log the arguments to this function to Tcl var ::echo_module */
for ( i = 0; i < argc; i++ )
{
appendToEchoModule( pVtab.interp, argv[i] );
}
 
/* Invoke sqlite3_declare_vtab and set up other members of the echo_vtab
** structure. If an error occurs, delete the sqlite3_vtab structure and
** return an error code.
*/
rc = echoDeclareVtab( pVtab, db );
if ( rc != SQLITE_OK )
{
//object obj = ppVtab;
//echoDestructor( ref obj );
//obj = null;
ppVtab = null;
return rc;
}
 
/* Success. Set ppVtab and return */
ppVtab = pVtab;//.base;
return SQLITE_OK;
}
 
/*
** Echo virtual table module xCreate method.
*/
static int echoCreate(
sqlite3 db,
object pAux,
int argc,
string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
)
{
int rc = SQLITE_OK;
appendToEchoModule( ( (EchoModule)pAux ).interp, "xCreate" );
rc = echoConstructor( db, pAux, argc, argv, out ppVtab, out pzErr );
 
/* If there were two arguments passed to the module at the SQL level
** (i.e. "CREATE VIRTUAL TABLE tbl USING echo(arg1, arg2)"), then
** the second argument is used as a table name. Attempt to create
** such a table with a single column, "logmsg". This table will
** be used to log calls to the xUpdate method. It will be deleted
** when the virtual table is DROPed.
**
** Note: The main point of this is to test that we can drop tables
** from within an xDestroy method call.
*/
if ( rc == SQLITE_OK && argc == 5 )
{
string zSql;
echo_vtab pVtab = (echo_vtab)ppVtab;
pVtab.zLogName = sqlite3_mprintf( "%s", argv[4] );
zSql = sqlite3_mprintf( "CREATE TABLE %Q(logmsg)", pVtab.zLogName );
rc = sqlite3_exec( db, zSql, 0, 0, 0 );
//sqlite3_free(zSql);
if ( rc != SQLITE_OK )
{
pzErr = sqlite3_mprintf( "%s", sqlite3_errmsg( db ) );
}
}
 
if ( ppVtab != null && rc != SQLITE_OK )
{
//object obj = ppVtab;
//echoDestructor( ref obj );
//obj = null;
ppVtab = null;
}
 
if ( rc == SQLITE_OK )
{
( (echo_vtab)ppVtab ).inTransaction = 1;
}
 
return rc;
}
 
/*
** Echo virtual table module xConnect method.
*/
static int echoConnect(
sqlite3 db,
object pAux,
int argc,
string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
)
{
appendToEchoModule( ( (EchoModule)pAux ).interp, "xConnect" );
return echoConstructor( db, pAux, argc, argv, out ppVtab, out pzErr );
}
 
/*
** Echo virtual table module xDisconnect method.
*/
static int echoDisconnect( ref object pVtab )
{
appendToEchoModule( ( (echo_vtab)pVtab ).interp, "xDisconnect" );
return echoDestructor( ref pVtab );
}
 
/*
** Echo virtual table module xDestroy method.
*/
static int echoDestroy( ref object pVtab )
{
int rc = SQLITE_OK;
echo_vtab p = (echo_vtab)pVtab;
appendToEchoModule( ( (echo_vtab)pVtab ).interp, "xDestroy" );
 
/* Drop the "log" table, if one exists (see echoCreate() for details) */
if ( p != null && !String.IsNullOrEmpty( p.zLogName ) )
{
string zSql;
zSql = sqlite3_mprintf( "DROP TABLE %Q", p.zLogName );
rc = sqlite3_exec( p.db, zSql, 0, 0, 0 );
//sqlite3_free(zSql);
}
 
if ( rc == SQLITE_OK )
{
rc = echoDestructor( ref pVtab );
}
return rc;
}
 
/*
** Echo virtual table module xOpen method.
*/
static int echoOpen( sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor )
{
echo_cursor pCur;
if ( simulateVtabError( (echo_vtab)pVTab, "xOpen" ) != 0 )
{
ppCursor = null;
return SQLITE_ERROR;
}
pCur = new echo_cursor();//sqlite3MallocZero( sizeof( echo_cursor ) );
ppCursor = (sqlite3_vtab_cursor)pCur;
return ( pCur != null ? SQLITE_OK : SQLITE_NOMEM );
}
 
/*
** Echo virtual table module xClose method.
*/
static int echoClose( ref sqlite3_vtab_cursor cur )
{
int rc = 0;
echo_cursor pCur = (echo_cursor)cur;
sqlite3_stmt pStmt = pCur.pStmt;
pCur.pStmt = null;
//sqlite3_free(pCur);
pCur = null;
rc = sqlite3_finalize( pStmt );
return rc;
}
 
/*
** Return non-zero if the cursor does not currently point to a valid record
** (i.e if the scan has finished), or zero otherwise.
*/
static int echoEof( sqlite3_vtab_cursor cur )
{
return ( ( (echo_cursor)cur ).pStmt != null ? 0 : 1 );
}
 
/*
** Echo virtual table module xNext method.
*/
static int echoNext( sqlite3_vtab_cursor cur )
{
int rc = SQLITE_OK;
echo_cursor pCur = (echo_cursor)cur;
 
if ( simulateVtabError( (echo_vtab)( cur.pVtab ), "xNext" ) != 0 )
{
return SQLITE_ERROR;
}
 
if ( pCur.pStmt != null )
{
rc = sqlite3_step( pCur.pStmt );
if ( rc == SQLITE_ROW )
{
rc = SQLITE_OK;
}
else
{
rc = sqlite3_finalize( pCur.pStmt );
pCur.pStmt = null;
}
}
 
return rc;
}
 
/*
** Echo virtual table module xColumn method.
*/
static int echoColumn( sqlite3_vtab_cursor cur, sqlite3_context ctx, int i )
{
int iCol = i + 1;
sqlite3_stmt pStmt = ( (echo_cursor)cur ).pStmt;
 
if ( simulateVtabError( (echo_vtab)( cur.pVtab ), "xColumn" ) != 0 )
{
return SQLITE_ERROR;
}
 
if ( null == pStmt )
{
sqlite3_result_null( ctx );
}
else
{
Debug.Assert( sqlite3_data_count( pStmt ) > iCol );
sqlite3_result_value( ctx, sqlite3_column_value( pStmt, iCol ) );
}
return SQLITE_OK;
}
 
/*
** Echo virtual table module xRowid method.
*/
static int echoRowid( sqlite3_vtab_cursor cur, out sqlite_int64 pRowid )
{
sqlite3_stmt pStmt = ( (echo_cursor)cur ).pStmt;
 
if ( simulateVtabError( (echo_vtab)( cur.pVtab ), "xRowid" ) != 0 )
{
pRowid = 0;
return SQLITE_ERROR;
}
 
pRowid = sqlite3_column_int64( pStmt, 0 );
return SQLITE_OK;
}
 
/*
** Compute a simple hash of the null terminated string zString.
**
** This module uses only sqlite3_index_info.idxStr, not
** sqlite3_index_info.idxNum. So to test idxNum, when idxStr is set
** in echoBestIndex(), idxNum is set to the corresponding hash value.
** In echoFilter(), code Debug.Assert()s that the supplied idxNum value is
** indeed the hash of the supplied idxStr.
*/
static int hashString( string zString )
{
int val = 0;
int ii;
for ( ii = 0; ii < zString.Length; ii++ )
{
val = ( val << 3 ) + (int)zString[ii];
}
return val;
}
 
/*
** Echo virtual table module xFilter method.
*/
static int echoFilter(
sqlite3_vtab_cursor pVtabCursor,
int idxNum, string idxStr,
int argc, sqlite3_value[] argv
)
{
int rc;
int i;
 
echo_cursor pCur = (echo_cursor)pVtabCursor;
echo_vtab pVtab = (echo_vtab)pVtabCursor.pVtab;
sqlite3 db = pVtab.db;
 
if ( simulateVtabError( pVtab, "xFilter" ) != 0 )
{
return SQLITE_ERROR;
}
 
/* Check that idxNum matches idxStr */
Debug.Assert( idxNum == hashString( idxStr ) );
 
/* Log arguments to the ::echo_module Tcl variable */
appendToEchoModule( pVtab.interp, "xFilter" );
appendToEchoModule( pVtab.interp, idxStr );
for ( i = 0; i < argc; i++ )
{
appendToEchoModule( pVtab.interp, sqlite3_value_text( argv[i] ) );
}
 
sqlite3_finalize( pCur.pStmt );
pCur.pStmt = null;
 
/* Prepare the SQL statement created by echoBestIndex and bind the
** runtime parameters passed to this function to it.
*/
rc = sqlite3_prepare( db, idxStr, -1, ref pCur.pStmt, 0 );
Debug.Assert( pCur.pStmt != null || rc != SQLITE_OK );
for ( i = 0; rc == SQLITE_OK && i < argc; i++ )
{
rc = sqlite3_bind_value( pCur.pStmt, i + 1, argv[i] );
}
 
/* If everything was successful, advance to the first row of the scan */
if ( rc == SQLITE_OK )
{
rc = echoNext( pVtabCursor );
}
 
return rc;
}
 
 
/*
** A helper function used by echoUpdate() and echoBestIndex() for
** manipulating strings in concert with the sqlite3_mprintf() function.
**
** Parameter pzStr points to a pointer to a string allocated with
** sqlite3_mprintf. The second parameter, zAppend, points to another
** string. The two strings are concatenated together and pzStr
** set to point at the result. The initial buffer pointed to by pzStr
** is deallocated via sqlite3_free().
**
** If the third argument, doFree, is true, then sqlite3_free() is
** also called to free the buffer pointed to by zAppend.
*/
static void string_concat( ref string pzStr, string zAppend, int doFree, ref int pRc )
{
string zIn = pzStr;
if ( null == zAppend && doFree != 0 && pRc == SQLITE_OK )
{
pRc = SQLITE_NOMEM;
}
if ( pRc != SQLITE_OK )
{
//sqlite3_free(zIn);
zIn = null;
}
else
{
if ( zIn != null )
{
string zTemp = zIn;
zIn = sqlite3_mprintf( "%s%s", zIn, zAppend );
//sqlite3_free(zTemp);
}
else
{
zIn = sqlite3_mprintf( "%s", zAppend );
}
//if ( null == zIn )
//{
// pRc = SQLITE_NOMEM;
//}
}
pzStr = zIn;
//if( doFree ){
// sqlite3_free(zAppend);
//}
}
 
/*
** The echo module implements the subset of query constraints and sort
** orders that may take advantage of SQLite indices on the underlying
** real table. For example, if the real table is declared as:
**
** CREATE TABLE real(a, b, c);
** CREATE INDEX real_index ON real(b);
**
** then the echo module handles WHERE or ORDER BY clauses that refer
** to the column "b", but not "a" or "c". If a multi-column index is
** present, only its left most column is considered.
**
** This xBestIndex method encodes the proposed search strategy as
** an SQL query on the real table underlying the virtual echo module
** table and stores the query in sqlite3_index_info.idxStr. The SQL
** statement is of the form:
**
** SELECT rowid, * FROM <real-table> ?<where-clause>? ?<order-by-clause>?
**
** where the <where-clause> and <order-by-clause> are determined
** by the contents of the structure pointed to by the pIdxInfo argument.
*/
static int echoBestIndex( sqlite3_vtab vtab, ref sqlite3_index_info pIdxInfo )
{
int ii;
string zQuery = "";
string zNew;
int nArg = 0;
string zSep = "WHERE";
echo_vtab pVtab = (echo_vtab)vtab;
sqlite3_stmt pStmt = null;
Tcl_Interp interp = pVtab.interp;
 
int nRow = 0;
int useIdx = 0;
int rc = SQLITE_OK;
int useCost = 0;
double cost = 0;
int isIgnoreUsable = 0;
if ( TCL.Tcl_GetVar( interp, "echo_module_ignore_usable", (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY ).ToString() != "" )
{
isIgnoreUsable = 1;
}
 
if ( simulateVtabError( pVtab, "xBestIndex" ) != 0 )
{
return SQLITE_ERROR;
}
 
/* Determine the number of rows in the table and store this value in local
** variable nRow. The 'estimated-cost' of the scan will be the number of
** rows in the table for a linear scan, or the log (base 2) of the
** number of rows if the proposed scan uses an index.
*/
if ( TCL.Tcl_GetVar( interp, "echo_module_cost", (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY ).ToString() != "" )
{
Double.TryParse( TCL.Tcl_GetVar( interp, "echo_module_cost", (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY ).ToString(), out cost );
useCost = 1;
}
else
{
zQuery = sqlite3_mprintf( "SELECT count() FROM %Q", pVtab.zTableName );
//if ( null == zQuery )
//{
// return SQLITE_NOMEM;
//}
rc = sqlite3_prepare( pVtab.db, zQuery, -1, ref pStmt, 0 );
//sqlite3_free(zQuery);
if ( rc != SQLITE_OK )
{
return rc;
}
sqlite3_step( pStmt );
nRow = sqlite3_column_int( pStmt, 0 );
rc = sqlite3_finalize( pStmt );
if ( rc != SQLITE_OK )
{
return rc;
}
}
 
zQuery = sqlite3_mprintf( "SELECT rowid, * FROM %Q", pVtab.zTableName );
//if ( null == zQuery )
//{
// return SQLITE_NOMEM;
//}
for ( ii = 0; ii < pIdxInfo.nConstraint; ii++ )
{
sqlite3_index_constraint pConstraint;
sqlite3_index_constraint_usage pUsage;
int iCol;
 
pConstraint = pIdxInfo.aConstraint[ii];
pUsage = pIdxInfo.aConstraintUsage[ii];
 
if ( 0 == isIgnoreUsable && !pConstraint.usable )
continue;
 
iCol = pConstraint.iColumn;
if ( iCol < 0 || pVtab.aIndex[iCol] != 0 )
{
string zCol;
string zOp = "";
useIdx = 1;
if ( iCol >= 0 )
{
zCol = pVtab.aCol[iCol];
}
else
{
zCol = "rowid";
}
switch ( pConstraint.op )
{
case SQLITE_INDEX_CONSTRAINT_EQ:
zOp = "=";
break;
case SQLITE_INDEX_CONSTRAINT_LT:
zOp = "<";
break;
case SQLITE_INDEX_CONSTRAINT_GT:
zOp = ">";
break;
case SQLITE_INDEX_CONSTRAINT_LE:
zOp = "<=";
break;
case SQLITE_INDEX_CONSTRAINT_GE:
zOp = ">=";
break;
case SQLITE_INDEX_CONSTRAINT_MATCH:
zOp = "LIKE";
break;
}
if ( zOp[0] == 'L' )
{
zNew = sqlite3_mprintf( " %s %s LIKE (SELECT '%%'||?||'%%')",
zSep, zCol );
}
else
{
zNew = sqlite3_mprintf( " %s %s %s ?", zSep, zCol, zOp );
}
string_concat( ref zQuery, zNew, 1, ref rc );
 
zSep = "AND";
pUsage.argvIndex = ++nArg;
pUsage.omit = true;
}
}
 
/* If there is only one term in the ORDER BY clause, and it is
** on a column that this virtual table has an index for, then consume
** the ORDER BY clause.
*/
if ( pIdxInfo.nOrderBy == 1 && ( pIdxInfo.aOrderBy[0].iColumn < 0 || pVtab.aIndex[pIdxInfo.aOrderBy[0].iColumn] != 0 ) )
{
int iCol = pIdxInfo.aOrderBy[0].iColumn;
string zCol;
string zDir = pIdxInfo.aOrderBy[0].desc ? "DESC" : "ASC";
if ( iCol >= 0 )
{
zCol = pVtab.aCol[iCol];
}
else
{
zCol = "rowid";
}
zNew = sqlite3_mprintf( " ORDER BY %s %s", zCol, zDir );
string_concat( ref zQuery, zNew, 1, ref rc );
pIdxInfo.orderByConsumed = true;
}
 
appendToEchoModule( pVtab.interp, "xBestIndex" );
;
appendToEchoModule( pVtab.interp, zQuery );
 
if ( null == zQuery )
{
return rc;
}
pIdxInfo.idxNum = hashString( zQuery );
pIdxInfo.idxStr = zQuery;
pIdxInfo.needToFreeIdxStr = 1;
if ( useCost != 0 )
{
pIdxInfo.estimatedCost = cost;
}
else if ( useIdx != 0 )
{
/* Approximation of log2(nRow). */
for ( ii = 0; ii < ( sizeof( int ) * 8 ); ii++ )
{
if ( ( nRow & ( 1 << ii ) ) != 0 )
{
pIdxInfo.estimatedCost = (double)ii;
}
}
}
else
{
pIdxInfo.estimatedCost = (double)nRow;
}
return rc;
}
 
/*
** The xUpdate method for echo module virtual tables.
**
** apData[0] apData[1] apData[2..]
**
** INTEGER DELETE
**
** INTEGER NULL (nCol args) UPDATE (do not set rowid)
** INTEGER INTEGER (nCol args) UPDATE (with SET rowid = <arg1>)
**
** NULL NULL (nCol args) INSERT INTO (automatic rowid value)
** NULL INTEGER (nCol args) INSERT (incl. rowid value)
**
*/
static int echoUpdate(
sqlite3_vtab vtab,
int nData,
sqlite3_value[] apData,
out sqlite_int64 pRowid
)
{
echo_vtab pVtab = (echo_vtab)vtab;
sqlite3 db = pVtab.db;
int rc = SQLITE_OK;
 
pRowid = 0;
sqlite3_stmt pStmt = null;
string z = ""; /* SQL statement to execute */
int bindArgZero = 0; /* True to bind apData[0] to sql var no. nData */
int bindArgOne = 0; /* True to bind apData[1] to sql var no. 1 */
int i; /* Counter variable used by for loops */
 
Debug.Assert( nData == pVtab.nCol + 2 || nData == 1 );
 
/* Ticket #3083 - make sure we always start a transaction prior to
** making any changes to a virtual table */
Debug.Assert( pVtab.inTransaction != 0 );
 
if ( simulateVtabError( pVtab, "xUpdate" ) != 0 )
{
return SQLITE_ERROR;
}
 
/* If apData[0] is an integer and nData>1 then do an UPDATE */
if ( nData > 1 && sqlite3_value_type( apData[0] ) == SQLITE_INTEGER )
{
string zSep = " SET";
z = sqlite3_mprintf( "UPDATE %Q", pVtab.zTableName );
//if ( null == z )
//{
// rc = SQLITE_NOMEM;
//}
 
bindArgOne = ( apData[1] != null && sqlite3_value_type( apData[1] ) == SQLITE_INTEGER )?1:0;
bindArgZero = 1;
 
if ( bindArgOne != 0 )
{
string_concat( ref z, " SET rowid=?1 ", 0, ref rc );
zSep = ",";
}
for ( i = 2; i < nData; i++ )
{
if ( apData[i] == null )
continue;
string_concat( ref z, sqlite3_mprintf(
"%s %Q=?%d", zSep, pVtab.aCol[i - 2], i ), 1, ref rc );
zSep = ",";
}
string_concat( ref z, sqlite3_mprintf( " WHERE rowid=?%d", nData ), 1, ref rc );
}
 
/* If apData[0] is an integer and nData==1 then do a DELETE */
else if ( nData == 1 && sqlite3_value_type( apData[0] ) == SQLITE_INTEGER )
{
z = sqlite3_mprintf( "DELETE FROM %Q WHERE rowid = ?1", pVtab.zTableName );
//if ( null == z )
//{
// rc = SQLITE_NOMEM;
//}
bindArgZero = 1;
}
 
/* If the first argument is NULL and there are more than two args, INSERT */
else if ( nData > 2 && sqlite3_value_type( apData[0] ) == SQLITE_NULL )
{
int ii;
string zInsert = "";
string zValues = "";
 
zInsert = sqlite3_mprintf( "INSERT INTO %Q (", pVtab.zTableName );
//if ( null == zInsert )
//{
// rc = SQLITE_NOMEM;
//}
if ( sqlite3_value_type( apData[1] ) == SQLITE_INTEGER )
{
bindArgOne = 1;
zValues = sqlite3_mprintf( "?" );
string_concat( ref zInsert, "rowid", 0, ref rc );
}
 
Debug.Assert( ( pVtab.nCol + 2 ) == nData );
for ( ii = 2; ii < nData; ii++ )
{
string_concat( ref zInsert,
sqlite3_mprintf( "%s%Q", !String.IsNullOrEmpty(zValues) ? ", " : "", pVtab.aCol[ii - 2] ), 1, ref rc );
string_concat( ref zValues,
sqlite3_mprintf( "%s?%d", !String.IsNullOrEmpty( zValues ) ? ", " : "", ii ), 1, ref rc );
}
 
string_concat( ref z, zInsert, 1, ref rc );
string_concat( ref z, ") VALUES(", 0, ref rc );
string_concat( ref z, zValues, 1, ref rc );
string_concat( ref z, ")", 0, ref rc );
}
 
/* Anything else is an error */
else
{
Debug.Assert( false );
return SQLITE_ERROR;
}
 
if ( rc == SQLITE_OK )
{
rc = sqlite3_prepare( db, z, -1, ref pStmt, 0 );
}
Debug.Assert( rc != SQLITE_OK || pStmt != null );
//sqlite3_free(z);
if ( rc == SQLITE_OK )
{
if ( bindArgZero != 0 )
{
sqlite3_bind_value( pStmt, nData, apData[0] );
}
if ( bindArgOne != 0 )
{
sqlite3_bind_value( pStmt, 1, apData[1] );
}
for ( i = 2; i < nData && rc == SQLITE_OK; i++ )
{
if ( apData[i] != null )
rc = sqlite3_bind_value( pStmt, i, apData[i] );
}
if ( rc == SQLITE_OK )
{
sqlite3_step( pStmt );
rc = sqlite3_finalize( pStmt );
}
else
{
sqlite3_finalize( pStmt );
}
}
 
if (/* pRowid != 0 && */ rc == SQLITE_OK )
{
pRowid = sqlite3_last_insert_rowid( db );
}
if ( rc != SQLITE_OK )
{
vtab.zErrMsg = sqlite3_mprintf( "echo-vtab-error: %s", sqlite3_errmsg( db ) );
}
 
return rc;
}
 
/*
** xBegin, xSync, xCommit and xRollback callbacks for echo module
** virtual tables. Do nothing other than add the name of the callback
** to the $::echo_module Tcl variable.
*/
static int echoTransactionCall( sqlite3_vtab vtab, string zCall )
{
string z;
echo_vtab pVtab = (echo_vtab)vtab;
z = sqlite3_mprintf( "echo(%s)", pVtab.zTableName );
//if( z==null ) return SQLITE_NOMEM;
appendToEchoModule( pVtab.interp, zCall );
appendToEchoModule( pVtab.interp, z );
//sqlite3_free(z);
return SQLITE_OK;
}
static int echoBegin( sqlite3_vtab vtab )
{
int rc;
echo_vtab pVtab = (echo_vtab)vtab;
Tcl_Interp interp = pVtab.interp;
string zVal;
 
/* Ticket #3083 - do not start a transaction if we are already in
** a transaction */
Debug.Assert( 0 == pVtab.inTransaction );
 
if ( simulateVtabError( pVtab, "xBegin" ) != 0 )
{
return SQLITE_ERROR;
}
 
rc = echoTransactionCall( vtab, "xBegin" );
 
if ( rc == SQLITE_OK )
{
/* Check if the $::echo_module_begin_fail variable is defined. If it is,
** and it is set to the name of the real table underlying this virtual
** echo module table, then cause this xSync operation to fail.
*/
zVal = TCL.Tcl_GetVar( interp, "echo_module_begin_fail", TCL.VarFlag.GLOBAL_ONLY ).ToString();
if ( zVal != null && 0 == zVal.CompareTo( pVtab.zTableName ) )
{
rc = SQLITE_ERROR;
}
}
if ( rc == SQLITE_OK )
{
pVtab.inTransaction = 1;
}
return rc;
}
static int echoSync( sqlite3_vtab vtab )
{
int rc;
echo_vtab pVtab = (echo_vtab)vtab;
Tcl_Interp interp = pVtab.interp;
string zVal;
 
/* Ticket #3083 - Only call xSync if we have previously started a
** transaction */
Debug.Assert( pVtab.inTransaction != 0 );
 
if ( simulateVtabError( pVtab, "xSync" ) != 0 )
{
return SQLITE_ERROR;
}
 
rc = echoTransactionCall( vtab, "xSync" );
 
if ( rc == SQLITE_OK )
{
/* Check if the $::echo_module_sync_fail variable is defined. If it is,
** and it is set to the name of the real table underlying this virtual
** echo module table, then cause this xSync operation to fail.
*/
zVal = TCL.Tcl_GetVar( interp, "echo_module_sync_fail", TCL.VarFlag.GLOBAL_ONLY ).ToString();
if ( zVal != "" && 0 == zVal.CompareTo( pVtab.zTableName ) )
{
rc = -1;
}
}
return rc;
}
static int echoCommit( sqlite3_vtab vtab )
{
echo_vtab pVtab = (echo_vtab)vtab;
int rc;
 
/* Ticket #3083 - Only call xCommit if we have previously started
** a transaction */
Debug.Assert( pVtab.inTransaction != 0 );
 
if ( simulateVtabError( pVtab, "xCommit" ) != 0 )
{
return SQLITE_ERROR;
}
 
sqlite3BeginBenignMalloc();
rc = echoTransactionCall( vtab, "xCommit" );
sqlite3EndBenignMalloc();
pVtab.inTransaction = 0;
return rc;
}
static int echoRollback( sqlite3_vtab vtab )
{
int rc;
echo_vtab pVtab = (echo_vtab)vtab;
 
/* Ticket #3083 - Only call xRollback if we have previously started
** a transaction */
Debug.Assert( pVtab.inTransaction != 0 );
 
rc = echoTransactionCall( vtab, "xRollback" );
pVtab.inTransaction = 0;
return rc;
}
 
/*
** Implementation of "GLOB" function on the echo module. Pass
** all arguments to the ::echo_glob_overload procedure of TCL
** and return the result of that procedure as a string.
*/
static void overloadedGlobFunction(
sqlite3_context pContext,
int nArg,
sqlite3_value[] apArg
)
{
Tcl_Interp interp = (Interp)sqlite3_user_data( pContext );
TclObject str = null;
int i;
int rc;
TCL.Tcl_DStringInit( out str );
TCL.Tcl_DStringAppendElement( str, "::echo_glob_overload" );
for ( i = 0; i < nArg; i++ )
{
TCL.Tcl_DStringAppendElement( str, " " + sqlite3_value_text( apArg[i] ) );
}
 
rc = TCL.Tcl_EvalObjEx( interp, str, 0 );// rc = TCL.Tcl_Eval( interp, TCL.Tcl_DStringValue( ref str ) );
TCL.Tcl_DStringFree( ref str );
if ( rc != 0 )
{
sqlite3_result_error( pContext, TCL.Tcl_GetStringResult( interp ), -1 );
}
else
{
sqlite3_result_text( pContext, TCL.Tcl_GetStringResult( interp ),
-1, SQLITE_TRANSIENT );
}
TCL.Tcl_ResetResult( interp );
}
 
/*
** This is the xFindFunction implementation for the echo module.
** SQLite calls this routine when the first argument of a function
** is a column of an echo virtual table. This routine can optionally
** override the implementation of that function. It will choose to
** do so if the function is named "glob", and a TCL command named
** ::echo_glob_overload exists.
*/
static int echoFindFunction(
sqlite3_vtab vtab,
int nArg,
string zFuncName,
ref dxFunc pxFunc, //void (**pxFunc)(sqlite3_context*,int,sqlite3_value),
ref object ppArg
)
{
echo_vtab pVtab = (echo_vtab)vtab;
Tcl_Interp interp = pVtab.interp;
Tcl_CmdInfo info;
if ( !zFuncName.StartsWith( "glob", StringComparison.InvariantCultureIgnoreCase ) )
{
return 0;
}
TCL.Tcl_GetCommandInfo( interp, "::echo_glob_overload", out info );
if ( info ==null)
{
return 0;
}
pxFunc = overloadedGlobFunction;
ppArg = interp;
return 1;
}
 
static int echoRename( sqlite3_vtab vtab, string zNewName )
{
int rc = SQLITE_OK;
echo_vtab p = (echo_vtab)vtab;
 
if ( simulateVtabError( p, "xRename" ) != 0 )
{
return SQLITE_ERROR;
}
 
if ( p.isPattern != 0 )
{
int nThis = p.zThis.Length;
string zSql = sqlite3_mprintf( "ALTER TABLE %s RENAME TO %s%s",
p.zTableName, zNewName, p.zTableName.Substring(nThis)
);
rc = sqlite3_exec( p.db, zSql, 0, 0, 0 );
//sqlite3_free( zSql );
}
 
return rc;
}
 
/*
** A virtual table module that merely "echos" the contents of another
** table (like an SQL VIEW).
*/
static sqlite3_module echoModule = new sqlite3_module(
0, /* iVersion */
echoCreate,
echoConnect,
echoBestIndex,
echoDisconnect,
echoDestroy,
echoOpen, /* xOpen - open a cursor */
echoClose, /* xClose - close a cursor */
echoFilter, /* xFilter - configure scan constraints */
echoNext, /* xNext - advance a cursor */
echoEof, /* xEof */
echoColumn, /* xColumn - read data */
echoRowid, /* xRowid - read data */
echoUpdate, /* xUpdate - write data */
echoBegin, /* xBegin - begin transaction */
echoSync, /* xSync - sync transaction */
echoCommit, /* xCommit - commit transaction */
echoRollback, /* xRollback - rollback transaction */
echoFindFunction, /* xFindFunction - function overloading */
echoRename /* xRename - rename the table */
);
 
/*
** Decode a pointer to an sqlite3 object.
*/
//extern int getDbPointer(Tcl_Interp interp, string zA, sqlite3 ppDb);
 
static int moduleDestroy( ref object p )
{
p = null;// sqlite3_free( p );
return SQLITE_OK;
}
 
/*
** Register the echo virtual table module.
*/
static int register_echo_module(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
;
;
EchoModule pMod;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
pMod = new EchoModule();//sqlite3_malloc(sizeof(EchoModule));
pMod.interp = interp;
sqlite3_create_module_v2( db, "echo", echoModule, pMod, moduleDestroy );
return TCL.TCL_OK;
}
 
/*
** Tcl interface to sqlite3_declare_vtab, invoked as follows from Tcl:
**
** sqlite3_declare_vtab DB SQL
*/
static int declare_vtab(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
int rc;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB SQL" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
rc = sqlite3_declare_vtab( db, TCL.Tcl_GetString( objv[2] ) );
if ( rc != SQLITE_OK )
{
TCL.Tcl_SetResult( interp, sqlite3_errmsg( db ), TCL.TCL_VOLATILE );
return TCL.TCL_ERROR;
}
return TCL.TCL_OK;
}
 
#endif //* ifndef SQLITE_OMIT_VIRTUALTABLE */
 
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetest8_Init( Tcl_Interp interp )
{
#if !SQLITE_OMIT_VIRTUALTABLE
//static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
// void *clientData;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[]{
new _aObjCmd( "register_echo_module", register_echo_module, 0 ),
new _aObjCmd( "sqlite3_declare_vtab", declare_vtab, 0 ),
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++)
{
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, null );
}
#endif
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test9_c.cs
@@ -0,0 +1,243 @@
using System.Diagnostics;
using System.Text;
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite3_stmt = Community.CsharpSqlite.Sqlite3.Vdbe;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
public partial class Sqlite3
{
/*
** 2007 March 29
**
** 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 obscure tests of the C-interface required
** for completeness. Test code is written in C for these cases
** as there is not much point in binding to Tcl.
*************************************************************************
** 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-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
**
*************************************************************************
*/
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
 
/*
** c_collation_test
*/
static int c_collation_test(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
string zErrFunction = "N/A";
sqlite3 db = null;
 
int rc;
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
/* Open a database. */
rc = sqlite3_open( ":memory:", out db );
if ( rc != SQLITE_OK )
{
zErrFunction = "sqlite3_open";
goto error_out;
}
 
rc = sqlite3_create_collation( db, "collate", 456, null, null );
if ( rc != SQLITE_MISUSE )
{
sqlite3_close( db );
zErrFunction = "sqlite3_create_collation";
goto error_out;
}
 
sqlite3_close( db );
return TCL.TCL_OK;
 
error_out:
TCL.Tcl_ResetResult( interp );
TCL.Tcl_AppendResult( interp, "Error testing function: ", zErrFunction, null );
return TCL.TCL_ERROR;
}
 
/*
** c_realloc_test
*/
static int c_realloc_test(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
object p;
string zErrFunction = "N/A";
 
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
p = sqlite3Malloc( 5 );
if ( p == null )
{
zErrFunction = "sqlite3Malloc";
goto error_out;
}
 
/* Test that realloc()ing a block of memory to a negative size is
** the same as free()ing that memory.
*/
//TODO -- ignore realloc
//p = sqlite3_realloc(p, -1);
//if( p!=null ){
// zErrFunction = "sqlite3_realloc";
// goto error_out;
//}
 
return TCL.TCL_OK;
 
error_out:
TCL.Tcl_ResetResult( interp );
TCL.Tcl_AppendResult( interp, "Error testing function: ", zErrFunction );
return TCL.TCL_ERROR;
}
 
 
/*
** c_misuse_test
*/
static int c_misuse_test(
object clientdata, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
string zErrFunction = "N/A";
sqlite3 db = null;
sqlite3_stmt pStmt;
int rc;
 
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
/* Open a database. Then close it again. We need to do this so that
** we have a "closed database handle" to pass to various API functions.
*/
rc = sqlite3_open( ":memory:", out db );
if ( rc != SQLITE_OK )
{
zErrFunction = "sqlite3_open";
goto error_out;
}
sqlite3_close( db );
 
 
rc = sqlite3_errcode( db );
if ( rc != SQLITE_MISUSE )
{
zErrFunction = "sqlite3_errcode";
goto error_out;
}
 
pStmt = new sqlite3_stmt();
pStmt.pc = 1234;
rc = sqlite3_prepare( db, (StringBuilder)null, 0, ref pStmt, 0 );
if ( rc != SQLITE_MISUSE )
{
zErrFunction = "sqlite3_prepare";
goto error_out;
}
Debug.Assert( pStmt == null ); /* Verify that pStmt is zeroed even on a MISUSE error */
 
 
pStmt = new sqlite3_stmt();
pStmt.pc = 1234;
rc = sqlite3_prepare_v2( db, null, 0, ref pStmt, 0 );
if ( rc != SQLITE_MISUSE )
{
zErrFunction = "sqlite3_prepare_v2";
goto error_out;
}
Debug.Assert( pStmt == null );
 
#if !SQLITE_OMIT_UTF16
pStmt = (sqlite3_stmt)1234;
rc = sqlite3_prepare16( db, null, 0, ref pStmt, 0 );
if( rc!=SQLITE_MISUSE ){
zErrFunction = "sqlite3_prepare16";
goto error_out;
}
Debug.Assert( pStmt==0 );
pStmt = (sqlite3_stmt)1234;
rc = sqlite3_prepare16_v2( db, null, 0, ref pStmt, 0 );
if( rc!=SQLITE_MISUSE ){
zErrFunction = "sqlite3_prepare16_v2";
goto error_out;
}
Debug.Assert( pStmt==0 );
#endif
 
return TCL.TCL_OK;
 
error_out:
TCL.Tcl_ResetResult( interp );
TCL.Tcl_AppendResult( interp, "Error testing function: ", zErrFunction );
return TCL.TCL_ERROR;
}
 
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetest9_Init( Tcl_Interp interp )
{
//static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
// void *object;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[] {
new _aObjCmd( "c_misuse_test", c_misuse_test, 0 ),
new _aObjCmd( "c_realloc_test", c_realloc_test, 0 ),
new _aObjCmd( "c_collation_test", c_collation_test, 0 ),
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )
{//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, null );
}
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test_autoext_c.cs
@@ -0,0 +1,200 @@
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite3_value = Sqlite3.Mem;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
public partial class Sqlite3
{
/*
** 2006 August 23
**
** 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.
**
*************************************************************************
** Test extension for testing the sqlite3_auto_extension() function.
*************************************************************************
** 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-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
**
*************************************************************************
*/
//#include "tcl.h"
//#include "sqlite3ext.h"
 
#if !SQLITE_OMIT_LOAD_EXTENSION
//static int SQLITE_EXTENSION_INIT1 = null;
static sqlite3_api_routines sqlite3_api = null;
 
/*
** The sqr() SQL function returns the square of its input value.
*/
static void sqrFunc(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
double r = sqlite3_value_double( argv[0] );
sqlite3_result_double( context, r * r );
}
 
/*
** This is the entry point to register the extension for the sqr() function.
*/
static int sqr_init(
sqlite3 db,
ref string pzErrMsg,
sqlite3_api_routines pApi
)
{
sqlite3_api = pApi; // SQLITE_EXTENSION_INIT2( pApi );
sqlite3_create_function( db, "sqr", 1, SQLITE_ANY, 0, sqrFunc, null, null );
return 0;
}
 
/*
** The cube() SQL function returns the cube of its input value.
*/
static void cubeFunc(
sqlite3_context context,
int argc,
sqlite3_value[] argv
)
{
double r = sqlite3_value_double( argv[0] );
sqlite3_result_double( context, r * r * r );
}
 
/*
** This is the entry point to register the extension for the cube() function.
*/
static int cube_init(
sqlite3 db,
ref string pzErrMsg,
sqlite3_api_routines pApi
)
{
sqlite3_api = pApi; //SQLITE_EXTENSION_INIT2( pApi );
sqlite3_create_function( db, "cube", 1, SQLITE_ANY, 0, cubeFunc, null, null );
return 0;
}
 
/*
** This is a broken extension entry point
*/
static int broken_init(
sqlite3 db,
ref string pzErrMsg,
sqlite3_api_routines pApi
)
{
string zErr;
sqlite3_api = pApi; //SQLITE_EXTENSION_INIT2( pApi );
zErr = sqlite3_mprintf( "broken autoext!" );
pzErrMsg = zErr;
return 1;
}
 
/*
** tclcmd: sqlite3_auto_extension_sqr
**
** Register the "sqr" extension to be loaded automatically.
*/
static int autoExtSqrObjCmd(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc = sqlite3_auto_extension( sqr_init );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return SQLITE_OK;
}
 
/*
** tclcmd: sqlite3_auto_extension_cube
**
** Register the "cube" extension to be loaded automatically.
*/
static int autoExtCubeObjCmd(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc = sqlite3_auto_extension( cube_init );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return SQLITE_OK;
}
 
/*
** tclcmd: sqlite3_auto_extension_broken
**
** Register the broken extension to be loaded automatically.
*/
static int autoExtBrokenObjCmd(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc = sqlite3_auto_extension( (dxInit)broken_init );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return SQLITE_OK;
}
 
#else
// static void sqlite3_reset_auto_extension() { }
#endif //* SQLITE_OMIT_LOAD_EXTENSION */
 
 
/*
** tclcmd: sqlite3_reset_auto_extension
**
** Reset all auto-extensions
*/
static int resetAutoExtObjCmd(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_reset_auto_extension();
return SQLITE_OK;
}
 
 
/*
** This procedure registers the TCL procs defined in this file.
*/
public static int Sqlitetest_autoext_Init( Tcl_Interp interp )
{
#if !SQLITE_OMIT_LOAD_EXTENSION
TCL.Tcl_CreateObjCommand( interp, "sqlite3_auto_extension_sqr",
autoExtSqrObjCmd, null, null );
TCL.Tcl_CreateObjCommand( interp, "sqlite3_auto_extension_cube",
autoExtCubeObjCmd, null, null );
TCL.Tcl_CreateObjCommand( interp, "sqlite3_auto_extension_broken",
autoExtBrokenObjCmd, null, null );
#endif
TCL.Tcl_CreateObjCommand( interp, "sqlite3_reset_auto_extension",
resetAutoExtObjCmd, null, null );
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test_backup_c.cs
@@ -0,0 +1,207 @@
using ClientData = System.Object;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
 
public partial class Sqlite3
{
/*
** 2009 January 28
**
** 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 test logic for the sqlite3_backup() interface.
*************************************************************************
** 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-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
**
*************************************************************************
*/
//#include "tcl.h"
//#include <sqlite3.h>
//#include <assert.h>
 
/* These functions are implemented in test1.c. */
//int getDbPointer(Tcl_Interp *, string , sqlite3 *);
//string sqlite3TestErrorName(int);
 
enum BackupSubCommandEnum
{
BACKUP_STEP,
BACKUP_FINISH,
BACKUP_REMAINING,
BACKUP_PAGECOUNT
};
 
struct BackupSubCommand
{
public string zCmd;
public BackupSubCommandEnum eCmd;
public int nArg;
public string zArg;
 
public BackupSubCommand( string zCmd, BackupSubCommandEnum eCmd, int nArg, string zArg )
{
this.zCmd = zCmd;
this.eCmd = eCmd;
this.nArg = nArg;
this.zArg = zArg;
}
}
 
static int Tcl_GetIndexFromObjStruct( Interp interp, TclObject to, BackupSubCommand[] table, int len, string msg, int flags, out int index )
{
string zCmd = to.ToString();
for ( index = 0; index < len; index++ )
{
if ( zCmd == table[index].zCmd )
return 0;
}
return 1;
}
 
static int backupTestCmd(
ClientData clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
BackupSubCommand[] aSub = new BackupSubCommand[] {
new BackupSubCommand("step", BackupSubCommandEnum.BACKUP_STEP , 1, "npage" ),
new BackupSubCommand("finish", BackupSubCommandEnum.BACKUP_FINISH , 0, "" ),
new BackupSubCommand("remaining", BackupSubCommandEnum.BACKUP_REMAINING , 0, "" ),
new BackupSubCommand("pagecount", BackupSubCommandEnum.BACKUP_PAGECOUNT , 0, "" ),
new BackupSubCommand(null,0,0,null)
};
 
sqlite3_backup p = (sqlite3_backup)clientData;
int iCmd = 0;
int rc;
 
rc = Tcl_GetIndexFromObjStruct(
interp, objv[1], aSub, aSub.Length, "option", 0, out iCmd
);
if ( rc != TCL.TCL_OK )
{
return rc;
}
if ( objc != ( 2 + aSub[iCmd].nArg ) )
{
TCL.Tcl_WrongNumArgs( interp, 2, objv, aSub[iCmd].zArg );
return TCL.TCL_ERROR;
}
 
switch ( aSub[iCmd].eCmd )
{
 
case BackupSubCommandEnum.BACKUP_FINISH:
{
string zCmdName;
WrappedCommand cmdInfo = null;
zCmdName = TCL.Tcl_GetString( objv[0] );
TCL.Tcl_GetCommandInfo( interp, zCmdName, out cmdInfo );
cmdInfo.deleteProc = null;
TCL.Tcl_SetCommandInfo( interp, zCmdName, cmdInfo );
TCL.Tcl_DeleteCommand( interp, zCmdName );
 
rc = sqlite3_backup_finish( p );
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_STATIC );
break;
}
 
case BackupSubCommandEnum.BACKUP_STEP:
{
int nPage = 0;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out nPage ) )
{
return TCL.TCL_ERROR;
}
rc = sqlite3_backup_step( p, nPage );
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_STATIC );
break;
}
 
case BackupSubCommandEnum.BACKUP_REMAINING:
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_backup_remaining( p ) ) );
break;
 
case BackupSubCommandEnum.BACKUP_PAGECOUNT:
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_backup_pagecount( p ) ) );
break;
}
 
return TCL.TCL_OK;
}
 
static void backupTestFinish( ref ClientData clientData )
{
sqlite3_backup pBackup = (sqlite3_backup)clientData;
sqlite3_backup_finish( pBackup );
}
 
/*
** sqlite3_backup CMDNAME DESTHANDLE DESTNAME SRCHANDLE SRCNAME
**
*/
static int backupTestInit(
ClientData clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3_backup pBackup;
sqlite3 pDestDb = null;
sqlite3 pSrcDb = null;
string zDestName;
string zSrcName;
string zCmd;
 
if ( objc != 6 )
{
TCL.Tcl_WrongNumArgs(
interp, 1, objv, "CMDNAME DESTHANDLE DESTNAME SRCHANDLE SRCNAME"
);
return TCL.TCL_ERROR;
}
 
zCmd = TCL.Tcl_GetString( objv[1] );
getDbPointer( interp, TCL.Tcl_GetString( objv[2] ), out pDestDb );
zDestName = TCL.Tcl_GetString( objv[3] );
getDbPointer( interp, TCL.Tcl_GetString( objv[4] ), out pSrcDb );
zSrcName = TCL.Tcl_GetString( objv[5] );
 
pBackup = sqlite3_backup_init( pDestDb, zDestName, pSrcDb, zSrcName );
if ( null == pBackup )
{
TCL.Tcl_AppendResult( interp, "sqlite3_backup_init() failed" );
return TCL.TCL_ERROR;
}
 
TCL.Tcl_CreateObjCommand( interp, zCmd, (Interp.dxObjCmdProc)backupTestCmd, pBackup, (Interp.dxCmdDeleteProc)backupTestFinish );
TCL.Tcl_SetObjResult( interp, objv[1] );
return TCL.TCL_OK;
}
 
public static int Sqlitetestbackup_Init( Tcl_Interp interp )
{
TCL.Tcl_CreateObjCommand( interp, "sqlite3_backup", backupTestInit, 0, null );
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test_btree_c.cs
@@ -0,0 +1,85 @@
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
 
public partial class Sqlite3
{
/*
** 2007 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.
**
*************************************************************************
** Code for testing the btree.c module in SQLite. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
*************************************************************************
** 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-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
**
*************************************************************************
*/
//#include "btreeInt.h"
//#include <tcl.h>
 
/*
** Usage: sqlite3_shared_cache_report
**
** Return a list of file that are shared and the number of
** references to each file.
*/
static int sqlite3BtreeSharedCacheReport(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if !SQLITE_OMIT_SHARED_CACHE
extern BtShared *sqlite3SharedCacheList;
BtShared *pBt;
Tcl_Obj *pRet = TCL.Tcl_NewObj();
for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){
string zFile = sqlite3PagerFilename(pBt->pPager);
Tcl_ListObjAppendElement(interp, pRet, TCL.TCL_NewStringObj(zFile, -1));
Tcl_ListObjAppendElement(interp, pRet, TCL.TCL_NewIntObj(pBt->nRef));
}
Tcl_SetObjResult(interp, pRet);
#endif
return TCL.TCL_OK;
}
 
/*
** Print debugging information about all cursors to standard output.
*/
static void sqlite3BtreeCursorList( Btree p )
{
#if SQLITE_DEBUG
BtCursor pCur;
BtShared pBt = p.pBt;
for ( pCur = pBt.pCursor; pCur != null; pCur = pCur.pNext )
{
MemPage pPage = pCur.apPage[pCur.iPage];
string zMode = pCur.wrFlag != 0 ? "rw" : "ro";
sqlite3DebugPrintf( "CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n",
pCur, pCur.pgnoRoot, zMode,
pPage != null ? pPage.pgno : 0, pCur.aiIdx[pCur.iPage],
( pCur.eState == CURSOR_VALID ) ? "" : " eof"
);
}
#endif
}
}
#endif
}
/trunk/testfixture/src/test_config_c.cs
@@ -0,0 +1,636 @@
using System.Diagnostics;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using Tcl_Interp = tcl.lang.Interp;
#endif
 
public partial class Sqlite3
{
/*
** 2007 May 7
**
** 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 used for testing the SQLite system.
** None of the code in this file goes into a deliverable build.
**
** The focus of this file is providing the TCL testing layer
** access to compile-time constants.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
 
#if TCLSH
//#include "sqliteLimit.h"
 
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
 
/*** Macro to stringify the results of the evaluation a pre-processor
** macro. i.e. so that STRINGVALUE(SQLITE_NOMEM) -> "7".
*/
//#define STRINGVALUE2(x) #x
//#define STRINGVALUE(x) STRINGVALUE2(x)
static string STRINGVALUE( int x )
{
return x.ToString();
}
 
/*
** This routine sets entries in the global ::sqlite_options() array variable
** according to the compile-time configuration of the database. Test
** procedures use this to determine when tests should be omitted.
*/
static void set_options( Tcl_Interp interp )
{
 
TCL.Tcl_SetVar2( interp, "sqlite_options", "malloc", "0", TCL.TCL_GLOBAL_ONLY );
 
#if SQLITE_32BIT_ROWID
TCL.Tcl_SetVar2( interp, "sqlite_options", "rowid32", "1", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "rowid32", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_CASE_SENSITIVE_LIKE
TCL.Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "casesensitivelike", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_DEBUG
TCL.Tcl_SetVar2( interp, "sqlite_options", "debug", "1", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "debug", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_DISABLE_DIRSYNC
TCL.Tcl_SetVar2(interp, "sqlite_options", "dirsync", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "dirsync", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_DISABLE_LFS
TCL.Tcl_SetVar2( interp, "sqlite_options", "lfs", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "lfs", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if FALSE // /* def SQLITE_MEMDEBUG */
TCL.Tcl_SetVar2( interp, "sqlite_options", "memdebug", "1", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "memdebug", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_8_3_NAMES
TCL.Tcl_SetVar2(interp, "sqlite_options", "8_3_names", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "8_3_names", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_MEMSYS3
TCL.Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "mem3", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_MEMSYS5
TCL.Tcl_SetVar2(interp, "sqlite_options", "mem5", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "mem5", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_MUTEX_OMIT
TCL.Tcl_SetVar2( interp, "sqlite_options", "mutex", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "mutex", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_MUTEX_NOOP
TCL.Tcl_SetVar2(interp, "sqlite_options", "mutex_noop", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "mutex_noop", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_ALTERTABLE
TCL.Tcl_SetVar2(interp, "sqlite_options", "altertable", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "altertable", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_ANALYZE
TCL.Tcl_SetVar2(interp, "sqlite_options", "analyze", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "analyze", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_ATOMIC_WRITE
TCL.Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "atomicwrite", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_ATTACH
TCL.Tcl_SetVar2(interp, "sqlite_options", "attach", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "attach", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_AUTHORIZATION
TCL.Tcl_SetVar2( interp, "sqlite_options", "auth", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp, "sqlite_options", "auth", "1", TCL.TCL_GLOBAL_ONLY);
#endif
 
#if SQLITE_OMIT_AUTOINCREMENT
TCL.Tcl_SetVar2(interp, "sqlite_options", "autoinc", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "autoinc", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_AUTOMATIC_INDEX
TCL.Tcl_SetVar2(interp, "sqlite_options", "autoindex", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "autoindex", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_AUTORESET
Tcl_SetVar2(interp, "sqlite_options", "autoreset", "0", TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "autoreset", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_AUTOVACUUM
TCL.Tcl_SetVar2( interp, "sqlite_options", "autovacuum", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "autovacuum", "1", TCL.TCL_GLOBAL_ONLY );
#endif // * SQLITE_OMIT_AUTOVACUUM */
#if !SQLITE_DEFAULT_AUTOVACUUM
TCL.Tcl_SetVar2( interp, "sqlite_options", "default_autovacuum", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp,"sqlite_options","default_autovacuum",
STRINGVALUE(SQLITE_DEFAULT_AUTOVACUUM), TCL.TCL_GLOBAL_ONLY);
#endif
 
#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
TCL.Tcl_SetVar2(interp, "sqlite_options", "between_opt", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "between_opt", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_BUILTIN_TEST
TCL.Tcl_SetVar2(interp, "sqlite_options", "builtin_test", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "builtin_test", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_BLOB_LITERAL
TCL.Tcl_SetVar2(interp, "sqlite_options", "bloblit", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "bloblit", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_CAST
TCL.Tcl_SetVar2(interp, "sqlite_options", "cast", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "cast", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_CHECK
TCL.Tcl_SetVar2(interp, "sqlite_options", "check", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "check", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_COLUMN_METADATA
TCL.Tcl_SetVar2( interp, "sqlite_options", "columnmetadata", "1", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "columnmetadata", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
TCL.Tcl_SetVar2( interp, "sqlite_options", "oversize_cell_check", "1",
TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp, "sqlite_options", "oversize_cell_check", "0",
TCL.TCL_GLOBAL_ONLY);
#endif
 
#if SQLITE_OMIT_COMPILEOPTION_DIAGS
TCL.Tcl_SetVar2(interp, "sqlite_options", "compileoption_diags", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "compileoption_diags", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_COMPLETE
TCL.Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "complete", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_COMPOUND_SELECT
TCL.Tcl_SetVar2(interp, "sqlite_options", "compound", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "compound", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
TCL.Tcl_SetVar2( interp, "sqlite_options", "conflict", "1", TCL.TCL_GLOBAL_ONLY );
 
#if SQLITE_OS_UNIX
TCL.Tcl_SetVar2(interp, "sqlite_options", "crashtest", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "crashtest", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_DATETIME_FUNCS
TCL.Tcl_SetVar2(interp, "sqlite_options", "datetime", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "datetime", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_DECLTYPE
TCL.Tcl_SetVar2(interp, "sqlite_options", "decltype", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "decltype", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_DEPRECATED
TCL.Tcl_SetVar2( interp, "sqlite_options", "deprecated", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "deprecated", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_DISKIO
TCL.Tcl_SetVar2(interp, "sqlite_options", "diskio", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "diskio", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_EXPLAIN
TCL.Tcl_SetVar2(interp, "sqlite_options", "explain", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "explain", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_FLOATING_POINT
TCL.Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "floatingpoint", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_FOREIGN_KEY
TCL.Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "foreignkey", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_FTS1
TCL.Tcl_SetVar2(interp, "sqlite_options", "fts1", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "fts1", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_FTS2
TCL.Tcl_SetVar2(interp, "sqlite_options", "fts2", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "fts2", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_FTS3
TCL.Tcl_SetVar2(interp, "sqlite_options", "fts3", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "fts3", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_GET_TABLE
TCL.Tcl_SetVar2( interp, "sqlite_options", "gettable", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp, "sqlite_options", "gettable", "1", TCL.TCL_GLOBAL_ONLY);
#endif
 
#if SQLITE_ENABLE_ICU
TCL.Tcl_SetVar2(interp, "sqlite_options", "icu", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "icu", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_INCRBLOB
TCL.Tcl_SetVar2( interp, "sqlite_options", "incrblob", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "incrblob", "1", TCL.TCL_GLOBAL_ONLY );
#endif // * SQLITE_OMIT_AUTOVACUUM */
 
#if SQLITE_OMIT_INTEGRITY_CHECK
TCL.Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "integrityck", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if !SQLITE_DEFAULT_FILE_FORMAT //SQLITE_DEFAULT_FILE_FORMAT && SQLITE_DEFAULT_FILE_FORMAT==1
TCL.Tcl_SetVar2( interp, "sqlite_options", "legacyformat", "1", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "legacyformat", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_LIKE_OPTIMIZATION
TCL.Tcl_SetVar2(interp, "sqlite_options", "like_opt", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "like_opt", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_LOAD_EXTENSION
TCL.Tcl_SetVar2( interp, "sqlite_options", "load_ext", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "load_ext", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_LOCALTIME
TCL.Tcl_SetVar2(interp, "sqlite_options", "localtime", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "localtime", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_LOOKASIDE
TCL.Tcl_SetVar2( interp, "sqlite_options", "lookaside", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp, "sqlite_options", "lookaside", "1", TCL.TCL_GLOBAL_ONLY);
#endif
 
TCL.Tcl_SetVar2( interp, "sqlite_options", "long_double", "0", TCL.TCL_GLOBAL_ONLY );
//sizeof(LONGDOUBLE_TYPE)>sizeof(double) ? "1" : "0",
//TCL.TCL_GLOBAL_ONLY);
 
#if SQLITE_OMIT_MEMORYDB
TCL.Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "memorydb", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_MEMORY_MANAGEMENT
TCL.Tcl_SetVar2(interp, "sqlite_options", "memorymanage", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "memorymanage", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_OR_OPTIMIZATION
TCL.Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "or_opt", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_PAGER_PRAGMAS
TCL.Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "pager_pragmas", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_PRAGMA || SQLITE_OMIT_FLAG_PRAGMAS
TCL.Tcl_SetVar2(interp, "sqlite_options", "pragma", "0", TCL.TCL_GLOBAL_ONLY);
TCL.Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "pragma", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_PROGRESS_CALLBACK
TCL.Tcl_SetVar2(interp, "sqlite_options", "progress", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "progress", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_REINDEX
TCL.Tcl_SetVar2(interp, "sqlite_options", "reindex", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "reindex", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_RTREE
TCL.Tcl_SetVar2(interp, "sqlite_options", "rtree", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "rtree", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_SCHEMA_PRAGMAS
TCL.Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "schema_pragmas", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
TCL.Tcl_SetVar2(interp, "sqlite_options", "schema_version", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "schema_version", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_ENABLE_STAT2
TCL.Tcl_SetVar2( interp, "sqlite_options", "stat2", "1", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "stat2", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if !(SQLITE_ENABLE_LOCKING_STYLE)
# if (__APPLE__)
//# define SQLITE_ENABLE_LOCKING_STYLE 1
# else
//# define SQLITE_ENABLE_LOCKING_STYLE 0
# endif
#endif
#if SQLITE_ENABLE_LOCKING_STYLE && (__APPLE__)
TCL.Tcl_SetVar2(interp,"sqlite_options","lock_proxy_pragmas","1",TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "lock_proxy_pragmas", "0", TCL.TCL_GLOBAL_ONLY );
#endif
#if (SQLITE_PREFER_PROXY_LOCKING) && (__APPLE__)
TCL.Tcl_SetVar2(interp,"sqlite_options","prefer_proxy_locking","1",TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "prefer_proxy_locking", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_SHARED_CACHE
TCL.Tcl_SetVar2( interp, "sqlite_options", "shared_cache", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "shared_cache", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_SUBQUERY
TCL.Tcl_SetVar2(interp, "sqlite_options", "subquery", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "subquery", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_TCL_VARIABLE
TCL.Tcl_SetVar2(interp, "sqlite_options", "tclvar", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "tclvar", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
TCL.Tcl_SetVar2( interp, "sqlite_options", "threadsafe",
STRINGVALUE( SQLITE_THREADSAFE ), TCL.TCL_GLOBAL_ONLY );
Debug.Assert( sqlite3_threadsafe() == SQLITE_THREADSAFE );
 
#if SQLITE_OMIT_TEMPDB
TCL.Tcl_SetVar2(interp, "sqlite_options", "tempdb", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "tempdb", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_TRACE
TCL.Tcl_SetVar2(interp, "sqlite_options", "trace", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "trace", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_TRIGGER
TCL.Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "trigger", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
TCL.Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "truncate_opt", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_UTF16
TCL.Tcl_SetVar2( interp, "sqlite_options", "utf16", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp, "sqlite_options", "utf16", "1", TCL.TCL_GLOBAL_ONLY);
#endif
 
#if SQLITE_OMIT_VACUUM || SQLITE_OMIT_ATTACH
TCL.Tcl_SetVar2(interp, "sqlite_options", "vacuum", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "vacuum", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_VIEW
TCL.Tcl_SetVar2(interp, "sqlite_options", "view", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "view", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_OMIT_VIRTUALTABLE
TCL.Tcl_SetVar2( interp, "sqlite_options", "vtab", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL.TCL_GLOBAL_ONLY);
#endif
 
#if SQLITE_OMIT_WAL
TCL.Tcl_SetVar2( interp, "sqlite_options", "wal", "0", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2(interp, "sqlite_options", "wal", "1", TCL.TCL_GLOBAL_ONLY);
#endif
 
#if SQLITE_OMIT_WSD
TCL.Tcl_SetVar2(interp, "sqlite_options", "wsd", "0", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "wsd", "1", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if (SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !(SQLITE_OMIT_SUBQUERY)
TCL.Tcl_SetVar2( interp, "sqlite_options", "update_delete_limit", "1", TCL.TCL_GLOBAL_ONLY );
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "update_delete_limit", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if (SQLITE_ENABLE_UNLOCK_NOTIFY)
TCL.Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "unlock_notify", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_SECURE_DELETE
TCL.Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "secure_delete", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if SQLITE_MULTIPLEX_EXT_OVWR
TCL.Tcl_SetVar2(interp, "sqlite_options", "multiplex_ext_overwrite", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "multiplex_ext_overwrite", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
#if YYTRACKMAXSTACKDEPTH
TCL.Tcl_SetVar2(interp, "sqlite_options", "yytrackmaxstackdepth", "1", TCL.TCL_GLOBAL_ONLY);
#else
TCL.Tcl_SetVar2( interp, "sqlite_options", "yytrackmaxstackdepth", "0", TCL.TCL_GLOBAL_ONLY );
#endif
 
//#define LINKVAR(x) { \
// const int cv_ ## x = SQLITE_ ## x; \
// TCL.Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \
// TCL.Tcl_LINK_INT | TCL.Tcl_LINK_READ_ONLY); }
 
 
//LINKVAR( MAX_LENGTH );
//LINKVAR( MAX_COLUMN );
//LINKVAR( MAX_SQL_LENGTH );
//LINKVAR( MAX_EXPR_DEPTH );
//LINKVAR( MAX_COMPOUND_SELECT );
//LINKVAR( MAX_VDBE_OP );
//LINKVAR( MAX_FUNCTION_ARG );
//LINKVAR( MAX_VARIABLE_NUMBER );
//LINKVAR( MAX_PAGE_SIZE );
//LINKVAR( MAX_PAGE_COUNT );
//LINKVAR( MAX_LIKE_PATTERN_LENGTH );
//LINKVAR( MAX_TRIGGER_DEPTH );
//LINKVAR( DEFAULT_TEMP_CACHE_SIZE );
//LINKVAR( DEFAULT_CACHE_SIZE );
//LINKVAR( DEFAULT_PAGE_SIZE );
//LINKVAR( DEFAULT_FILE_FORMAT );
//LINKVAR( MAX_ATTACHED );
 
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_LENGTH", SQLITE_MAX_LENGTH, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_COLUMN", SQLITE_MAX_COLUMN, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_SQL_LENGTH", SQLITE_MAX_SQL_LENGTH, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_EXPR_DEPTH", SQLITE_MAX_EXPR_DEPTH, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_COMPOUND_SELECT", SQLITE_MAX_COMPOUND_SELECT, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_VDBE_OP", SQLITE_MAX_VDBE_OP, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_FUNCTION_ARG", SQLITE_MAX_FUNCTION_ARG, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_VARIABLE_NUMBER", SQLITE_MAX_VARIABLE_NUMBER, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_PAGE_SIZE", SQLITE_MAX_PAGE_SIZE, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_PAGE_COUNT", SQLITE_MAX_PAGE_COUNT, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_LIKE_PATTERN_LENGTH", SQLITE_MAX_LIKE_PATTERN_LENGTH, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_TRIGGER_DEPTH", SQLITE_MAX_TRIGGER_DEPTH, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_DEFAULT_TEMP_CACHE_SIZE", SQLITE_DEFAULT_TEMP_CACHE_SIZE, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_DEFAULT_CACHE_SIZE", SQLITE_DEFAULT_CACHE_SIZE, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_DEFAULT_PAGE_SIZE", SQLITE_DEFAULT_PAGE_SIZE, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_DEFAULT_FILE_FORMAT", SQLITE_DEFAULT_FILE_FORMAT, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
TCL.Tcl_LinkVar( interp, "SQLITE_MAX_ATTACHED", SQLITE_MAX_ATTACHED, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
 
{
int cv_TEMP_STORE = SQLITE_TEMP_STORE;
TCL.Tcl_LinkVar( interp, "TEMP_STORE", cv_TEMP_STORE, VarFlags.SQLITE3_LINK_INT | VarFlags.SQLITE3_LINK_READ_ONLY );
}
}
 
 
/*
** Register commands with the TCL interpreter.
*/
public static int Sqliteconfig_Init( Tcl_Interp interp )
{
set_options( interp );
return TCL.TCL_OK;
}
#endif
}
}
/trunk/testfixture/src/test_func_c.cs
@@ -0,0 +1,696 @@
using System;
using System.Diagnostics;
using System.Text;
 
using i64 = System.Int64;
using u8 = System.Byte;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
public partial class Sqlite3
{
/*
** 2008 March 19
**
** 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.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** implements new SQL functions used by the test scripts.
*************************************************************************
** 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: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
**
*************************************************************************
*/
//#include "sqlite3.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
//#include <assert.h>
 
 
/*
** Allocate nByte bytes of space using sqlite3Malloc(). If the
** allocation fails, call sqlite3_result_error_nomem() to notify
** the database handle that malloc() has failed.
*/
static Object testContextMalloc( sqlite3_context context, int nByte )
{
Object z = new Object();// sqlite3Malloc( nByte );
if ( z == null && nByte > 0 )
{
sqlite3_result_error_nomem( context );
}
return z;
}
 
/*
** This function generates a string of random characters. Used for
** generating test data.
*/
static void randStr( sqlite3_context context, int argc, sqlite3_value[] argv )
{
string zSrc =
"abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"0123456789" +
".-!,:*^+=_|?/<> ";
int iMin, iMax, n, i;
i64 r = 0;
 
StringBuilder zBuf = new StringBuilder( 1000 );
 
/* It used to be possible to call randstr() with any number of arguments,
** but now it is registered with SQLite as requiring exactly 2.
*/
Debug.Assert( argc == 2 );
 
iMin = sqlite3_value_int( argv[0] );
if ( iMin < 0 )
iMin = 0;
if ( iMin >= zBuf.Capacity )
iMin = zBuf.Capacity - 1;
iMax = sqlite3_value_int( argv[1] );
if ( iMax < iMin )
iMax = iMin;
if ( iMax >= zBuf.Capacity )
iMax = zBuf.Capacity - 1;
n = iMin;
if ( iMax > iMin )
{
sqlite3_randomness( sizeof( i64 ), ref r );
r &= 0x7fffffff;
n += (int)( r % ( iMax + 1 - iMin ) );
}
Debug.Assert( n < zBuf.Capacity );//sizeof( zBuf ) );
i64 zRan = 0;
for ( i = 0; i < n; i++ )
{
sqlite3_randomness( 1, ref zRan );
zBuf.Append( zSrc[(int)( Math.Abs( zRan ) % ( zSrc.Length - 1 ) )] );
}
//zBuf[n] = 0;
sqlite3_result_text( context, zBuf, n, SQLITE_TRANSIENT );
}
 
/*
** The following two SQL functions are used to test returning a text
** result with a destructor. Function 'test_destructor' takes one argument
** and returns the same argument interpreted as TEXT. A destructor is
** passed with the sqlite3_result_text() call.
**
** SQL function 'test_destructor_count' returns the number of outstanding
** allocations made by 'test_destructor';
**
** WARNING: Not threadsafe.
*/
static int test_destructor_count_var = 0;
static void destructor( ref string p )
{
string zVal = p;
Debug.Assert( zVal != null );
//zVal--;
sqlite3DbFree( null, ref zVal );
test_destructor_count_var--;
}
static void test_destructor(
sqlite3_context pCtx, /* Function context */
int nArg, /* Number of function arguments */
sqlite3_value[] argv /* Values for all function arguments */
)
{
String zVal;
int len;
 
test_destructor_count_var++;
Debug.Assert( nArg == 1 );
if ( sqlite3_value_type( argv[0] ) == SQLITE_NULL )
return;
len = sqlite3_value_bytes( argv[0] );
zVal = "";//testContextMalloc( pCtx, len + 3 );
if ( null == zVal )
{
return;
}
//zVal[len+1] = 0;
//zVal[len+2] = 0;
//zVal++;
zVal = sqlite3_value_text( argv[0] );//memcpy(zVal, sqlite3_value_text(argv[0]), len);
 
sqlite3_result_text( pCtx, zVal, -1, destructor );
}
#if !SQLITE_OMIT_UTF16
static void test_destructor16(
//sqlite3_context pCtx, /* Function context */
//int nArg, /* Number of function arguments */
//sqlite3_value[] argv /* Values for all function arguments */
){
string zVal;
int len;
 
test_destructor_count_var++;
Debug.Assert(nArg==1 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
len = sqlite3_value_bytes16(argv[0]);
zVal = testContextMalloc(pCtx, len+3);
if( null==zVal ){
return;
}
zVal[len+1] = 0;
zVal[len+2] = 0;
zVal++;
memcpy(zVal, sqlite3_value_text16(argv[0]), len);
sqlite3_result_text16(pCtx, zVal, -1, destructor);
}
#endif
 
static void test_destructor_count(
sqlite3_context pCtx, /* Function context */
int nArg, /* Number of function arguments */
sqlite3_value[] argv /* Values for all function arguments */
)
{
sqlite3_result_int( pCtx, test_destructor_count_var );
}
 
/*
** The following aggregate function, test_agg_errmsg16(), takes zero
** arguments. It returns the text value returned by the sqlite3_errmsg16()
** API function.
*/
#if SQLITE_OMIT_BUILTIN_TEST
//void sqlite3BeginBenignMalloc(void);
//void sqlite3EndBenignMalloc(void);
#else
//#define sqlite3BeginBenignMalloc()
//#define sqlite3EndBenignMalloc()
#endif
static void test_agg_errmsg16_step( sqlite3_context a, int b, sqlite3_value[] c )
{
}
static void test_agg_errmsg16_final( sqlite3_context ctx )
{
#if !SQLITE_OMIT_UTF16
string z;
sqlite3 db = sqlite3_context_db_handle( ctx );
sqlite3_aggregate_context( ctx, 2048 );
sqlite3BeginBenignMalloc();
z = sqlite3_errmsg16( db );
sqlite3EndBenignMalloc();
sqlite3_result_text16( ctx, z, -1, SQLITE_TRANSIENT );
#endif
}
 
/*
** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata()
** interface.
**
** The test_auxdata() SQL function attempts to register each of its arguments
** as auxiliary data. If there are no prior registrations of aux data for
** that argument (meaning the argument is not a constant or this is its first
** call) then the result for that argument is 0. If there is a prior
** registration, the result for that argument is 1. The overall result
** is the individual argument results separated by spaces.
*/
static void free_test_auxdata( ref string p )
{
p = null;
sqlite3DbFree( null, ref p );
}
static void test_auxdata(
sqlite3_context pCtx, /* Function context */
int nArg, /* Number of function arguments */
sqlite3_value[] argv /* Values for all function arguments */
)
{
int i;
StringBuilder zRet = new StringBuilder( nArg * 2 );//testContextMalloc( pCtx, nArg * 2 );
if ( null == zRet )
return;
//memset(zRet, 0, nArg*2);
for ( i = 0; i < nArg; i++ )
{
string z = sqlite3_value_text( argv[i] );
if ( z != null )
{
int n;
string zAux = (string)sqlite3_get_auxdata( pCtx, i );
if ( zAux != null )
{
zRet.Append( '1' );//[i * 2] = '1';
Debug.Assert( zAux == z );//strcmp( zAux, z ) == 0 );
}
else
{
zRet.Append( '0' );//[i * 2] = '0';
}
n = z.Length;// strlen( z ) + 1;
zAux = "";//testContextMalloc( pCtx, n );
if ( zAux != null )
{
zAux = z.Substring( 0, n );// memcpy( zAux, z, n );
sqlite3_set_auxdata( pCtx, i, zAux );
}
zRet.Append( ' ' );// zRet[i * 2 + 1] = ' ';
}
}
sqlite3_result_text( pCtx, zRet, 2 * nArg - 1, free_test_auxdata );
}
 
/*
** A function to test error reporting from user functions. This function
** returns a copy of its first argument as the error message. If the
** second argument exists, it becomes the error code.
*/
static void test_error(
sqlite3_context pCtx, /* Function context */
int nArg, /* Number of function arguments */
sqlite3_value[] argv /* Values for all function arguments */
)
{
sqlite3_result_error( pCtx, sqlite3_value_text( argv[0] ), -1 );
if ( nArg == 2 )
{
sqlite3_result_error_code( pCtx, sqlite3_value_int( argv[1] ) );
}
}
 
/*
** Implementation of the counter(X) function. If X is an integer
** constant, then the first invocation will return X. The second X+1.
** and so forth. Can be used (for example) to provide a sequence number
** in a result set.
*/
//static void counterFunc(
//sqlite3_context pCtx, /* Function context */
//int nArg, /* Number of function arguments */
//sqlite3_value[] argv /* Values for all function arguments */
//){
// int *pCounter = (int)sqlite3_get_auxdata(pCtx, 0);
// if( pCounter==0 ){
// pCounter = sqlite3_malloc( sizeof(*pCounter) );
// if( pCounter==0 ){
// sqlite3_result_error_nomem(pCtx);
// return;
// }
// *pCounter = sqlite3_value_int(argv[0]);
// sqlite3_set_auxdata(pCtx, 0, pCounter, //sqlite3_free);
// }else{
// ++*pCounter;
// }
// sqlite3_result_int(pCtx, *pCounter);
//}
//
//
 
/*
** This function takes two arguments. It performance UTF-8/16 type
** conversions on the first argument then returns a copy of the second
** argument.
**
** This function is used in cases such as the following:
**
** SELECT test_isolation(x,x) FROM t1;
**
** We want to verify that the type conversions that occur on the
** first argument do not invalidate the second argument.
*/
static void test_isolation(
sqlite3_context pCtx, /* Function context */
int nArg, /* Number of function arguments */
sqlite3_value[] argv /* Values for all function arguments */
)
{
#if !SQLITE_OMIT_UTF16
sqlite3_value_text16(argv[0]);
sqlite3_value_text(argv[0]);
sqlite3_value_text16(argv[0]);
sqlite3_value_text(argv[0]);
#endif
sqlite3_result_value( pCtx, argv[1] );
}
 
/*
** Invoke an SQL statement recursively. The function result is the
** first column of the first row of the result set.
*/
static void test_eval(
sqlite3_context pCtx, /* Function context */
int nArg, /* Number of function arguments */
sqlite3_value[] argv /* Values for all function arguments */
)
{
sqlite3_stmt pStmt = new sqlite3_stmt();
int rc;
sqlite3 db = sqlite3_context_db_handle( pCtx );
string zSql;
 
zSql = sqlite3_value_text( argv[0] );
rc = sqlite3_prepare_v2( db, zSql, -1, ref pStmt, 0 );
if ( rc == SQLITE_OK )
{
rc = sqlite3_step( pStmt );
if ( rc == SQLITE_ROW )
{
sqlite3_result_value( pCtx, sqlite3_column_value( pStmt, 0 ) );
}
rc = sqlite3_finalize( pStmt );
}
if ( rc != 0 )
{
string zErr;
Debug.Assert( pStmt == null );
zErr = sqlite3_mprintf( "sqlite3_prepare_v2() error: %s", sqlite3_errmsg( db ) );
sqlite3_result_text( pCtx, zErr, -1, null );//sqlite3_free );
sqlite3_result_error_code( pCtx, rc );
}
}
 
class _aFuncs
{
public string zName;
public int nArg;
public u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */
public dxFunc xFunc;
public _aFuncs( string zName, int nArg, u8 eTextRep, dxFunc xFunc )
{
this.zName = zName;
this.nArg = nArg;
this.eTextRep = eTextRep;
this.xFunc = xFunc;
}
}
 
/*
** convert one character from hex to binary
*/
static int testHexChar( char c )
{
if ( c >= '0' && c <= '9' )
{
return c - '0';
}
else if ( c >= 'a' && c <= 'f' )
{
return c - 'a' + 10;
}
else if ( c >= 'A' && c <= 'F' )
{
return c - 'A' + 10;
}
return 0;
}
 
/*
** Convert hex to binary.
*/
static void testHexToBin( string zIn, ref string zOut )
{
for ( int zIx = 0; zIx < zIn.Length - 1; zIx += 2 )// zIn[0] && zIn[1] )
{
//*(zOut++) = (testHexChar(zIn[0])<<4) + testHexChar(zIn[1]);
zOut += ( testHexChar( zIn[zIx] ) << 4 ) + testHexChar( zIn[zIx + 1] );
//zIn += 2;
}
}
 
#if !SQLITE_OMIT_UTF16
/*
** hex_to_utf16be(HEX)
**
** Convert the input string from HEX into binary. Then return the
** result using sqlite3_result_text16le().
*/
static void testHexToUtf16be(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
int n;
string zIn;
string zOut;
Debug.Assert( nArg==1 );
n = sqlite3_value_bytes(argv[0]);
zIn = (const char)sqlite3_value_text(argv[0]);
zOut = sqlite3_malloc( n/2 );
if( zOut==0 ){
sqlite3_result_error_nomem(pCtx);
}else{
testHexToBin(zIn, zOut);
sqlite3_result_text16be(pCtx, zOut, n/2, sqlite3_free);
}
}
#endif
 
/*
** hex_to_utf8(HEX)
**
** Convert the input string from HEX into binary. Then return the
** result using sqlite3_result_text16le().
*/
static void testHexToUtf8(
sqlite3_context pCtx,
int nArg,
sqlite3_value[] argv
)
{
int n;
string zIn;
string zOut = "";
Debug.Assert( nArg == 1 );
n = sqlite3_value_bytes( argv[0] );
zIn = sqlite3_value_text( argv[0] );
//zOut = sqlite3_malloc( n/2 );
//if( zOut==0 ){
// sqlite3_result_error_nomem(pCtx);
//}else{
testHexToBin( zIn, ref zOut );
sqlite3_result_text( pCtx, zOut, n / 2, null );//sqlite3_free );
//}
}
 
#if !SQLITE_OMIT_UTF16
/*
** hex_to_utf16le(HEX)
**
** Convert the input string from HEX into binary. Then return the
** result using sqlite3_result_text16le().
*/
static void testHexToUtf16le(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **argv
){
int n;
string zIn;
string zOut;
Debug.Assert( nArg==1 );
n = sqlite3_value_bytes(argv[0]);
zIn = (const char)sqlite3_value_text(argv[0]);
zOut = sqlite3_malloc( n/2 );
if( zOut==0 ){
sqlite3_result_error_nomem(pCtx);
}else{
testHexToBin(zIn, zOut);
sqlite3_result_text16le(pCtx, zOut, n/2, sqlite3_free);
}
}
#endif
 
static int registerTestFunctions( sqlite3 db, ref string dummy1, sqlite3_api_routines dummy2 )
{
_aFuncs[] aFuncs = new _aFuncs[] {
new _aFuncs( "randstr", 2, SQLITE_UTF8, randStr ),
new _aFuncs( "test_destructor", 1, SQLITE_UTF8, test_destructor),
#if !SQLITE_OMIT_UTF16
{ "test_destructor16", 1, SQLITE_UTF8, test_destructor16},
{ "hex_to_utf16be", 1, SQLITE_UTF8, testHexToUtf16be},
{ "hex_to_utf16le", 1, SQLITE_UTF8, testHexToUtf16le},
#endif
new _aFuncs( "hex_to_utf8", 1, SQLITE_UTF8, testHexToUtf8),
new _aFuncs( "test_destructor_count", 0, SQLITE_UTF8, test_destructor_count),
new _aFuncs( "test_auxdata", -1, SQLITE_UTF8, test_auxdata),
new _aFuncs( "test_error", 1, SQLITE_UTF8, test_error),
new _aFuncs( "test_error", 2, SQLITE_UTF8, test_error),
new _aFuncs( "test_eval", 1, SQLITE_UTF8, test_eval),
new _aFuncs( "test_isolation", 2, SQLITE_UTF8, test_isolation),
//{ "test_counter", 2, SQLITE_UTF8, counterFunc},
};
int i;
 
for ( i = 0; i < aFuncs.Length; i++ )
{//sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
sqlite3_create_function( db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].eTextRep, 0, aFuncs[i].xFunc, null, null );
}
 
sqlite3_create_function( db, "test_agg_errmsg16", 0, SQLITE_ANY, 0, null,
test_agg_errmsg16_step, test_agg_errmsg16_final );
 
return SQLITE_OK;
}
 
/*
** TCLCMD: autoinstall_test_functions
**
** Invoke this TCL command to use sqlite3_auto_extension() to cause
** the standard set of test functions to be loaded into each new
** database connection.
*/
static int autoinstall_test_funcs(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
//extern int Md5_Register(sqlite3);
int rc = sqlite3_auto_extension( (dxInit)registerTestFunctions );
if ( rc == SQLITE_OK )
{
rc = sqlite3_auto_extension( (dxInit)Md5_Register );
}
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return TCL.TCL_OK;
}
 
 
/*
** A bogus step function and finalizer function.
*/
static void tStep( sqlite3_context a, int b, sqlite3_value[] c )
{
}
static void tFinal( sqlite3_context a )
{
}
 
 
/*
** tclcmd: abuse_create_function
**
** Make various calls to sqlite3_create_function that do not have valid
** parameters. Verify that the error condition is detected and reported.
*/
static int abuse_create_function(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
//extern int getDbPointer(Tcl_Interp*, const char*, sqlite3*);
sqlite3 db = null;
int rc;
int mxArg;
 
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
 
rc = sqlite3_create_function( db, "tx", 1, SQLITE_UTF8, 0, tStep, tStep, tFinal );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
rc = sqlite3_create_function( db, "tx", 1, SQLITE_UTF8, 0, tStep, tStep, null );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
rc = sqlite3_create_function( db, "tx", 1, SQLITE_UTF8, 0, tStep, null, tFinal );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
rc = sqlite3_create_function( db, "tx", 1, SQLITE_UTF8, 0, null, null, tFinal );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
rc = sqlite3_create_function( db, "tx", 1, SQLITE_UTF8, 0, null, tStep, null );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
rc = sqlite3_create_function( db, "tx", -2, SQLITE_UTF8, 0, tStep, null, null );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
rc = sqlite3_create_function( db, "tx", 128, SQLITE_UTF8, 0, tStep, null, null );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
rc = sqlite3_create_function( db, "funcxx" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789",
1, SQLITE_UTF8, 0, tStep, null, null );
if ( rc != SQLITE_MISUSE )
goto abuse_err;
 
/* This last function registration should actually work. Generate
** a no-op function (that always returns NULL) and which has the
** maximum-length function name and the maximum number of parameters.
*/
sqlite3_limit( db, SQLITE_LIMIT_FUNCTION_ARG, 10000 );
mxArg = sqlite3_limit( db, SQLITE_LIMIT_FUNCTION_ARG, -1 );
rc = sqlite3_create_function( db, "nullx" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789" +
"_123456789_123456789_123456789_123456789_123456789",
mxArg, SQLITE_UTF8, 0, tStep, null, null );
if ( rc != SQLITE_OK )
goto abuse_err;
 
return TCL.TCL_OK;
 
abuse_err:
TCL.Tcl_AppendResult( interp, "sqlite3_create_function abused test failed"
);
return TCL.TCL_ERROR;
}
 
 
/*
** Register commands with the TCL interpreter.
*/
public static int Sqlitetest_func_Init( Tcl_Interp interp )
{
//static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[] {
new _aObjCmd( "autoinstall_test_functions", autoinstall_test_funcs ),
new _aObjCmd( "abuse_create_function", abuse_create_function ),
};
int i;
//extern int Md5_Register(sqlite3);
 
for ( i = 0; i < aObjCmd.Length; i++ )
{//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName, aObjCmd[i].xProc, null, null );
}
sqlite3_initialize();
sqlite3_auto_extension( (dxInit)registerTestFunctions );
sqlite3_auto_extension( (dxInit)Md5_Register );
return TCL.TCL_OK;
}
}
#endif
}
 
/trunk/testfixture/src/test_fuzzer_c.cs
@@ -0,0 +1,1130 @@
using System;
using System.Diagnostics;
using System.Text;
 
using i64 = System.Int64;
using u8 = System.Byte;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite3_int64 = System.Int64;
using sqlite_int64 = System.Int64;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
 
using fuzzer_cost = System.Int32;
 
public partial class Sqlite3
{
/*
** 2011 March 24
**
** 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.
**
*************************************************************************
**
** Code for demonstartion virtual table that generates variations
** on an input word at increasing edit distances from the original.
**
** A fuzzer virtual table is created like this:
**
** CREATE VIRTUAL TABLE temp.f USING fuzzer;
**
** The name of the new virtual table in the example above is "f".
** Note that all fuzzer virtual tables must be TEMP tables. The
** "temp." prefix in front of the table name is required when the
** table is being created. The "temp." prefix can be omitted when
** using the table as long as the name is unambiguous.
**
** Before being used, the fuzzer needs to be programmed by giving it
** character transformations and a cost associated with each transformation.
** Examples:
**
** INSERT INTO f(cFrom,cTo,Cost) VALUES('','a',100);
**
** The above statement says that the cost of inserting a letter 'a' is
** 100. (All costs are integers. We recommend that costs be scaled so
** that the average cost is around 100.)
**
** INSERT INTO f(cFrom,cTo,Cost) VALUES('b','',87);
**
** The above statement says that the cost of deleting a single letter
** 'b' is 87.
**
** INSERT INTO f(cFrom,cTo,Cost) VALUES('o','oe',38);
** INSERT INTO f(cFrom,cTo,Cost) VALUES('oe','o',40);
**
** This third example says that the cost of transforming the single
** letter "o" into the two-letter sequence "oe" is 38 and that the
** cost of transforming "oe" back into "o" is 40.
**
** After all the transformation costs have been set, the fuzzer table
** can be queried as follows:
**
** SELECT word, distance FROM f
** WHERE word MATCH 'abcdefg'
** AND distance<200;
**
** This first query outputs the string "abcdefg" and all strings that
** can be derived from that string by appling the specified transformations.
** The strings are output together with their total transformation cost
** (called "distance") and appear in order of increasing cost. No string
** is output more than once. If there are multiple ways to transform the
** target string into the output string then the lowest cost transform is
** the one that is returned. In the example, the search is limited to
** strings with a total distance of less than 200.
**
** It is important to put some kind of a limit on the fuzzer output. This
** can be either in the form of a LIMIT clause at the end of the query,
** or better, a "distance<NNN" constraint where NNN is some number. The
** running time and memory requirement is exponential in the value of NNN
** so you want to make sure that NNN is not too big. A value of NNN that
** is about twice the average transformation cost seems to give good results.
**
** The fuzzer table can be useful for tasks such as spelling correction.
** Suppose there is a second table vocabulary(w) where the w column contains
** all correctly spelled words. Let $word be a word you want to look up.
**
** SELECT vocabulary.w FROM f, vocabulary
** WHERE f.word MATCH $word
** AND f.distance<=200
** AND f.word=vocabulary.w
** LIMIT 20
**
** The query above gives the 20 closest words to the $word being tested.
** (Note that for good performance, the vocubulary.w column should be
** indexed.)
**
** A similar query can be used to find all words in the dictionary that
** begin with some prefix $prefix:
**
** SELECT vocabulary.w FROM f, vocabulary
** WHERE f.word MATCH $prefix
** AND f.distance<=200
** AND vocabulary.w BETWEEN f.word AND (f.word || x'F7BFBFBF')
** LIMIT 50
**
** This last query will show up to 50 words out of the vocabulary that
** match or nearly match the $prefix.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
//#include "sqlite3.h"
//#include <stdlib.h>
//#include <string.h>
//#include <Debug.Assert.h>
//#include <stdio.h>
 
#if !SQLITE_OMIT_VIRTUALTABLE
 
/*
** Forward declaration of objects used by this implementation
*/
//typedef struct fuzzer_vtab fuzzer_vtab;
//typedef struct fuzzer_cursor fuzzer_cursor;
//typedef struct fuzzer_rule fuzzer_rule;
//typedef struct fuzzer_seen fuzzer_seen;
//typedef struct fuzzer_stem fuzzer_stem;
 
/*
** Type of the "cost" of an edit operation. Might be changed to
** "float" or "double" or "sqlite3_int64" in the future.
*/
//typedef int fuzzer_cost;
 
 
/*
** Each transformation rule is stored as an instance of this object.
** All rules are kept on a linked list sorted by rCost.
*/
class fuzzer_rule
{
public fuzzer_rule pNext; /* Next rule in order of increasing rCost */
public fuzzer_cost rCost; /* Cost of this transformation */
public int nFrom, nTo; /* Length of the zFrom and zTo strings */
public string zFrom; /* Transform from */
public string zTo = " "; /* Transform to (extra space appended) */
};
 
/*
** A stem object is used to generate variants. It is also used to record
** previously generated outputs.
**
** Every stem is added to a hash table as it is output. Generation of
** duplicate stems is suppressed.
**
** Active stems (those that might generate new outputs) are kepts on a linked
** list sorted by increasing cost. The cost is the sum of rBaseCost and
** pRule.rCost.
*/
class fuzzer_stem
{
public string zBasis; /* Word being fuzzed */
public int nBasis; /* Length of the zBasis string */
public fuzzer_rule pRule; /* Current rule to apply */
public int n; /* Apply pRule at this character offset */
public fuzzer_cost rBaseCost; /* Base cost of getting to zBasis */
public fuzzer_cost rCostX; /* Precomputed rBaseCost + pRule.rCost */
public fuzzer_stem pNext; /* Next stem in rCost order */
public fuzzer_stem pHash; /* Next stem with same hash on zBasis */
};
 
/*
** A fuzzer virtual-table object
*/
class fuzzer_vtab : sqlite3_vtab
{
//sqlite3_vtab base; /* Base class - must be first */
public string zClassName; /* Name of this class. Default: "fuzzer" */
public fuzzer_rule pRule; /* All active rules in this fuzzer */
public fuzzer_rule pNewRule; /* New rules to add when last cursor expires */
public int nCursor; /* Number of active cursors */
};
 
//#define FUZZER_HASH 4001 /* Hash table size */
const int FUZZER_HASH = 4001;
//#define FUZZER_NQUEUE 20 /* Number of slots on the stem queue */
const int FUZZER_NQUEUE = 20;
 
/* A fuzzer cursor object */
class fuzzer_cursor : sqlite3_vtab_cursor
{
//sqlite3_vtab_cursor base; /* Base class - must be first */
public sqlite3_int64 iRowid; /* The rowid of the current word */
public new fuzzer_vtab pVtab; /* The virtual table this cursor belongs to */
public fuzzer_cost rLimit; /* Maximum cost of any term */
public fuzzer_stem pStem; /* Stem with smallest rCostX */
public fuzzer_stem pDone; /* Stems already processed to completion */
public fuzzer_stem[] aQueue = new fuzzer_stem[FUZZER_NQUEUE]; /* Queue of stems with higher rCostX */
public int mxQueue; /* Largest used index in aQueue[] */
public string zBuf; /* Temporary use buffer */
public int nBuf; /* Bytes allocated for zBuf */
public int nStem; /* Number of stems allocated */
public fuzzer_rule nullRule = new fuzzer_rule(); /* Null rule used first */
public fuzzer_stem[] apHash = new fuzzer_stem[FUZZER_HASH]; /* Hash of previously generated terms */
};
 
/* Methods for the fuzzer module */
static int fuzzerConnect(
sqlite3 db,
object pAux,
int argc, string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
)
{
fuzzer_vtab pNew;
int n;
if ( !argv[1].StartsWith( "temp", StringComparison.CurrentCultureIgnoreCase ) )
{
pzErr = sqlite3_mprintf( "%s virtual tables must be TEMP", argv[0] );
ppVtab = null;
return SQLITE_ERROR;
}
//n = strlen(argv[0]) + 1;
pNew = new fuzzer_vtab();//sqlite3_malloc( sizeof(pNew) + n );
//if( pNew==0 ) return SQLITE_NOMEM;
//pNew.zClassName = (char*)&pNew[1];
pNew.zClassName = argv[0];//memcpy(pNew.zClassName, argv[0], n);
sqlite3_declare_vtab( db, "CREATE TABLE x(word,distance,cFrom,cTo,cost)" );
//memset(pNew, 0, sizeof(pNew));
pzErr = "";
ppVtab = pNew;
return SQLITE_OK;
}
/* Note that for this virtual table, the xCreate and xConnect
** methods are identical. */
 
static int fuzzerDisconnect( ref object pVtab )
{
fuzzer_vtab p = (fuzzer_vtab)pVtab;
Debug.Assert( p.nCursor == 0 );
do
{
while ( p.pRule != null )
{
fuzzer_rule pRule = p.pRule;
p.pRule = pRule.pNext;
pRule = null;//sqlite3_free(pRule);
}
p.pRule = p.pNewRule;
p.pNewRule = null;
} while ( p.pRule != null );
pVtab = null;//sqlite3_free(p);
return SQLITE_OK;
}
/* The xDisconnect and xDestroy methods are also the same */
 
/*
** The two input rule lists are both sorted in order of increasing
** cost. Merge them together into a single list, sorted by cost, and
** return a pointer to the head of that list.
*/
static fuzzer_rule fuzzerMergeRules( fuzzer_rule pA, fuzzer_rule pB )
{
fuzzer_rule head = new fuzzer_rule();
fuzzer_rule pTail;
 
pTail = head;
while ( pA != null && pB != null )
{
if ( pA.rCost <= pB.rCost )
{
pTail.pNext = pA;
pTail = pA;
pA = pA.pNext;
}
else
{
pTail.pNext = pB;
pTail = pB;
pB = pB.pNext;
}
}
if ( pA == null )
{
pTail.pNext = pB;
}
else
{
pTail.pNext = pA;
}
return head.pNext;
}
 
 
/*
** Open a new fuzzer cursor.
*/
static int fuzzerOpen( sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor )
{
fuzzer_vtab p = (fuzzer_vtab)pVTab;
fuzzer_cursor pCur;
pCur = new fuzzer_cursor();//= sqlite3_malloc( sizeof(pCur) );
///if( pCur==0 ) return SQLITE_NOMEM;
//memset(pCur, 0, sizeof(pCur));
pCur.pVtab = p;
ppCursor = pCur;
if ( p.nCursor == 0 && p.pNewRule != null )
{
uint i;
fuzzer_rule pX;
fuzzer_rule[] a = new fuzzer_rule[15];
//for(i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = 0;
while ( ( pX = p.pNewRule ) != null )
{
p.pNewRule = pX.pNext;
pX.pNext = null;
for ( i = 0; a[i] != null && i < a.Length; i++ )//<sizeof(a)/sizeof(a[0])-1; i++)
{
pX = fuzzerMergeRules( a[i], pX );
a[i] = null;
}
a[i] = fuzzerMergeRules( a[i], pX );
}
for ( pX = a[0], i = 1; i < a.Length; i++ )//sizeof(a)/sizeof(a[0]); i++)
{
pX = fuzzerMergeRules( a[i], pX );
}
p.pRule = fuzzerMergeRules( p.pRule, pX );
}
p.nCursor++;
return SQLITE_OK;
}
 
/*
** Free all stems in a list.
*/
static void fuzzerClearStemList( ref fuzzer_stem pStem )
{
//while( pStem ){
// fuzzer_stem pNext = pStem.pNext;
// sqlite3_free(pStem);
// pStem = pNext;
//}
pStem = null;
}
 
/*
** Free up all the memory allocated by a cursor. Set it rLimit to 0
** to indicate that it is at EOF.
*/
static void fuzzerClearCursor( fuzzer_cursor pCur, int clearHash )
{
int i;
fuzzerClearStemList( ref pCur.pStem );
fuzzerClearStemList( ref pCur.pDone );
for ( i = 0; i < FUZZER_NQUEUE; i++ )
fuzzerClearStemList( ref pCur.aQueue[i] );
pCur.rLimit = (fuzzer_cost)0;
if ( clearHash != 0 && pCur.nStem != 0 )
{
pCur.mxQueue = 0;
pCur.pStem = null;
pCur.pDone = null;
Array.Clear( pCur.aQueue, 0, pCur.aQueue.Length );//memset(pCur.aQueue, 0, sizeof(pCur.aQueue));
Array.Clear( pCur.apHash, 0, pCur.apHash.Length );//memset(pCur.apHash, 0, sizeof(pCur.apHash));
}
pCur.nStem = 0;
}
 
/*
** Close a fuzzer cursor.
*/
static int fuzzerClose( ref sqlite3_vtab_cursor cur )
{
fuzzer_cursor pCur = (fuzzer_cursor)cur;
fuzzerClearCursor( pCur, 0 );
//sqlite3_free(pCur.zBuf);
pCur.pVtab.nCursor--;
cur = null;//sqlite3_free( pCur );
return SQLITE_OK;
}
 
/*
** Compute the current output term for a fuzzer_stem.
*/
static int fuzzerRender(
fuzzer_stem pStem, /* The stem to be rendered */
ref string pzBuf, /* Write results into this buffer. realloc if needed */
ref int pnBuf /* Size of the buffer */
)
{
fuzzer_rule pRule = pStem.pRule;
int n;
string z;
 
n = pStem.nBasis + pRule.nTo - pRule.nFrom;
if ( ( pnBuf ) < n + 1 )
{
//(*pzBuf) = sqlite3_realloc((*pzBuf), n+100);
//if( (*pzBuf)==0 ) return SQLITE_NOMEM;
( pnBuf ) = n + 100;
}
n = pStem.n;
//z = pzBuf;
if ( n < 0 )
{
z = pStem.zBasis.Substring( 0, pStem.nBasis + 1 );//memcpy(z, pStem.zBasis, pStem.nBasis+1);
}
else
{
z = pStem.zBasis.Substring( 0, n );//memcpy( z, pStem.zBasis, n );
if ( pRule.nTo != 0 )
z += pRule.zTo.Substring( 0, pRule.nTo );//memcpy(&z[n], pRule.zTo, pRule.nTo);
z += pStem.zBasis.Substring( n + pRule.nFrom, pStem.nBasis - n - pRule.nFrom );
//memcpy(&z[n+pRule.nTo], &pStem.zBasis[n+pRule.nFrom], pStem.nBasis-n-pRule.nFrom+1);
}
pzBuf = z;
return SQLITE_OK;
}
 
/*
** Compute a hash on zBasis.
*/
static uint fuzzerHash( string z )
{
uint h = 0;
//while( *z ){ h = (h<<3) ^ (h>>29) ^ *(z++); }
for ( int i = 0; i < z.Length; i++ )
h = ( h << 3 ) ^ ( h >> 29 ) ^ (byte)z[i];
return h % FUZZER_HASH;
}
 
/*
** Current cost of a stem
*/
static fuzzer_cost fuzzerCost( fuzzer_stem pStem )
{
return pStem.rCostX = pStem.rBaseCost + pStem.pRule.rCost;
}
 
#if FALSE
/*
** Print a description of a fuzzer_stem on stderr.
*/
static void fuzzerStemPrint(
const char *zPrefix,
fuzzer_stem pStem,
const char *zSuffix
){
if( pStem.n<0 ){
fprintf(stderr, "%s[%s](%d)-.self%s",
zPrefix,
pStem.zBasis, pStem.rBaseCost,
zSuffix
);
}else{
char *zBuf = 0;
int nBuf = 0;
if( fuzzerRender(pStem, &zBuf, &nBuf)!=SQLITE_OK ) return;
fprintf(stderr, "%s[%s](%d)-.{%s}(%d)%s",
zPrefix,
pStem.zBasis, pStem.rBaseCost, zBuf, pStem.,
zSuffix
);
sqlite3_free(zBuf);
}
}
#endif
 
/*
** Return 1 if the string to which the cursor is point has already
** been emitted. Return 0 if not. Return -1 on a memory allocation
** failures.
*/
static int fuzzerSeen( fuzzer_cursor pCur, fuzzer_stem pStem )
{
uint h;
fuzzer_stem pLookup;
 
if ( fuzzerRender( pStem, ref pCur.zBuf, ref pCur.nBuf ) == SQLITE_NOMEM )
{
return -1;
}
h = fuzzerHash( pCur.zBuf );
pLookup = pCur.apHash[h];
while ( pLookup != null && pLookup.zBasis.CompareTo( pCur.zBuf ) != 0 )
{
pLookup = pLookup.pHash;
}
return pLookup != null ? 1 : 0;
}
 
/*
** Advance a fuzzer_stem to its next value. Return 0 if there are
** no more values that can be generated by this fuzzer_stem. Return
** -1 on a memory allocation failure.
*/
static int fuzzerAdvance( fuzzer_cursor pCur, fuzzer_stem pStem )
{
fuzzer_rule pRule;
while ( ( pRule = pStem.pRule ) != null )
{
while ( pStem.n < pStem.nBasis - pRule.nFrom )
{
pStem.n++;
if ( pRule.nFrom == 0
|| memcmp( pStem.zBasis.Substring( pStem.n ), pRule.zFrom, pRule.nFrom ) == 0//|| memcmp( &pStem.zBasis[pStem.n], pRule.zFrom, pRule.nFrom ) == 0
)
{
/* Found a rewrite case. Make sure it is not a duplicate */
int rc = fuzzerSeen( pCur, pStem );
if ( rc < 0 )
return -1;
if ( rc == 0 )
{
fuzzerCost( pStem );
return 1;
}
}
}
pStem.n = -1;
pStem.pRule = pRule.pNext;
if ( pStem.pRule != null && fuzzerCost( pStem ) > pCur.rLimit )
pStem.pRule = null;
}
return 0;
}
 
/*
** The two input stem lists are both sorted in order of increasing
** rCostX. Merge them together into a single list, sorted by rCostX, and
** return a pointer to the head of that new list.
*/
static fuzzer_stem fuzzerMergeStems( fuzzer_stem pA, fuzzer_stem pB )
{
fuzzer_stem head = new fuzzer_stem();
fuzzer_stem pTail;
 
pTail = head;
while ( pA != null && pB != null )
{
if ( pA.rCostX <= pB.rCostX )
{
pTail.pNext = pA;
pTail = pA;
pA = pA.pNext;
}
else
{
pTail.pNext = pB;
pTail = pB;
pB = pB.pNext;
}
}
if ( pA == null )
{
pTail.pNext = pB;
}
else
{
pTail.pNext = pA;
}
return head.pNext;
}
 
/*
** Load pCur.pStem with the lowest-cost stem. Return a pointer
** to the lowest-cost stem.
*/
static fuzzer_stem fuzzerLowestCostStem( fuzzer_cursor pCur )
{
fuzzer_stem pBest, pX;
int iBest;
int i;
 
if ( pCur.pStem == null )
{
iBest = -1;
pBest = null;
for ( i = 0; i <= pCur.mxQueue; i++ )
{
pX = pCur.aQueue[i];
if ( pX == null )
continue;
if ( pBest == null || pBest.rCostX > pX.rCostX )
{
pBest = pX;
iBest = i;
}
}
if ( pBest != null )
{
pCur.aQueue[iBest] = pBest.pNext;
pBest.pNext = null;
pCur.pStem = pBest;
}
}
return pCur.pStem;
}
 
/*
** Insert pNew into queue of pending stems. Then find the stem
** with the lowest rCostX and move it into pCur.pStem.
** list. The insert is done such the pNew is in the correct order
** according to fuzzer_stem.zBaseCost+fuzzer_stem.pRule.rCost.
*/
static fuzzer_stem fuzzerInsert( fuzzer_cursor pCur, fuzzer_stem pNew )
{
fuzzer_stem pX;
int i;
 
/* If pCur.pStem exists and is greater than pNew, then make pNew
** the new pCur.pStem and insert the old pCur.pStem instead.
*/
if ( ( pX = pCur.pStem ) != null && pX.rCostX > pNew.rCostX )
{
pNew.pNext = null;
pCur.pStem = pNew;
pNew = pX;
}
 
/* Insert the new value */
pNew.pNext = null;
pX = pNew;
for ( i = 0; i <= pCur.mxQueue; i++ )
{
if ( pCur.aQueue[i] != null )
{
pX = fuzzerMergeStems( pX, pCur.aQueue[i] );
pCur.aQueue[i] = null;
}
else
{
pCur.aQueue[i] = pX;
break;
}
}
if ( i > pCur.mxQueue )
{
if ( i < FUZZER_NQUEUE )
{
pCur.mxQueue = i;
pCur.aQueue[i] = pX;
}
else
{
Debug.Assert( pCur.mxQueue == FUZZER_NQUEUE - 1 );
pX = fuzzerMergeStems( pX, pCur.aQueue[FUZZER_NQUEUE - 1] );
pCur.aQueue[FUZZER_NQUEUE - 1] = pX;
}
}
//for ( i = 0; i <= pCur.mxQueue; i++ )
//{
// if (pCur.aQueue[i] == 0)
// fprintf (stderr, "%d null", i);
// else
// fprintf (stderr, "%d %s %d %d",i, pCur.aQueue[i].zBasis, pCur.aQueue[i].n, pCur.aQueue[i].rCostX );
//}
// fprintf (stderr, " (lowest %d )\n", fuzzerLowestCostStem(pCur).rCostX);
return fuzzerLowestCostStem( pCur );
}
 
/*
** Allocate a new fuzzer_stem. Add it to the hash table but do not
** link it into either the pCur.pStem or pCur.pDone lists.
*/
static fuzzer_stem fuzzerNewStem(
fuzzer_cursor pCur,
string zWord,
fuzzer_cost rBaseCost
)
{
fuzzer_stem pNew;
uint h;
 
pNew = new fuzzer_stem();//= sqlite3_malloc( sizeof(pNew) + strlen(zWord) + 1 );
//if( pNew==0 ) return 0;
//memset(pNew, 0, sizeof(pNew));
//pNew.zBasis = (char*)&pNew[1];
pNew.nBasis = zWord.Length;//strlen( zWord );
pNew.zBasis = zWord;//memcpy(pNew.zBasis, zWord, pNew.nBasis+1);
pNew.pRule = pCur.pVtab.pRule;
pNew.n = -1;
pNew.rBaseCost = pNew.rCostX = rBaseCost;
h = fuzzerHash( pNew.zBasis );
pNew.pHash = pCur.apHash[h];
pCur.apHash[h] = pNew;
pCur.nStem++;
return pNew;
}
 
 
/*
** Advance a cursor to its next row of output
*/
static int fuzzerNext( sqlite3_vtab_cursor cur )
{
fuzzer_cursor pCur = (fuzzer_cursor)cur;
int rc;
fuzzer_stem pStem, pNew;
 
pCur.iRowid++;
 
/* Use the element the cursor is currently point to to create
** a new stem and insert the new stem into the priority queue.
*/
pStem = pCur.pStem;
if ( pStem.rCostX > 0 )
{
rc = fuzzerRender( pStem, ref pCur.zBuf, ref pCur.nBuf );
if ( rc == SQLITE_NOMEM )
return SQLITE_NOMEM;
pNew = fuzzerNewStem( pCur, pCur.zBuf, pStem.rCostX );
if ( pNew != null )
{
if ( fuzzerAdvance( pCur, pNew ) == 0 )
{
pNew.pNext = pCur.pDone;
pCur.pDone = pNew;
}
else
{
if ( fuzzerInsert( pCur, pNew ) == pNew )
{
return SQLITE_OK;
}
}
}
else
{
return SQLITE_NOMEM;
}
}
 
/* Adjust the priority queue so that the first element of the
** stem list is the next lowest cost word.
*/
while ( ( pStem = pCur.pStem ) != null )
{
if ( fuzzerAdvance( pCur, pStem ) != 0 )
{
pCur.pStem = null;
pStem = fuzzerInsert( pCur, pStem );
if ( ( rc = fuzzerSeen( pCur, pStem ) ) != 0 )
{
if ( rc < 0 )
return SQLITE_NOMEM;
continue;
}
return SQLITE_OK; /* New word found */
}
pCur.pStem = null;
pStem.pNext = pCur.pDone;
pCur.pDone = pStem;
if ( fuzzerLowestCostStem( pCur ) != null )
{
rc = fuzzerSeen( pCur, pCur.pStem );
if ( rc < 0 )
return SQLITE_NOMEM;
if ( rc == 0 )
{
return SQLITE_OK;
}
}
}
 
/* Reach this point only if queue has been exhausted and there is
** nothing left to be output. */
pCur.rLimit = (fuzzer_cost)0;
return SQLITE_OK;
}
 
/*
** Called to "rewind" a cursor back to the beginning so that
** it starts its output over again. Always called at least once
** prior to any fuzzerColumn, fuzzerRowid, or fuzzerEof call.
*/
static int fuzzerFilter(
sqlite3_vtab_cursor pVtabCursor,
int idxNum, string idxStr,
int argc, sqlite3_value[] argv
)
{
fuzzer_cursor pCur = (fuzzer_cursor)pVtabCursor;
string zWord = "";
fuzzer_stem pStem;
 
fuzzerClearCursor( pCur, 1 );
pCur.rLimit = 2147483647;
if ( idxNum == 1 )
{
zWord = (string)sqlite3_value_text( argv[0] );
}
else if ( idxNum == 2 )
{
pCur.rLimit = (fuzzer_cost)sqlite3_value_int( argv[0] );
}
else if ( idxNum == 3 )
{
zWord = (string)sqlite3_value_text( argv[0] );
pCur.rLimit = (fuzzer_cost)sqlite3_value_int( argv[1] );
}
if ( zWord == null )
zWord = "";
pCur.pStem = pStem = fuzzerNewStem( pCur, zWord, (fuzzer_cost)0 );
if ( pStem == null )
return SQLITE_NOMEM;
pCur.nullRule.pNext = pCur.pVtab.pRule;
pCur.nullRule.rCost = 0;
pCur.nullRule.nFrom = 0;
pCur.nullRule.nTo = 0;
pCur.nullRule.zFrom = "";
pStem.pRule = pCur.nullRule;
pStem.n = pStem.nBasis;
pCur.iRowid = 1;
return SQLITE_OK;
}
 
/*
** Only the word and distance columns have values. All other columns
** return NULL
*/
static int fuzzerColumn( sqlite3_vtab_cursor cur, sqlite3_context ctx, int i )
{
fuzzer_cursor pCur = (fuzzer_cursor)cur;
if ( i == 0 )
{
/* the "word" column */
if ( fuzzerRender( pCur.pStem, ref pCur.zBuf, ref pCur.nBuf ) == SQLITE_NOMEM )
{
return SQLITE_NOMEM;
}
sqlite3_result_text( ctx, pCur.zBuf, -1, SQLITE_TRANSIENT );
}
else if ( i == 1 )
{
/* the "distance" column */
sqlite3_result_int( ctx, pCur.pStem.rCostX );
}
else
{
/* All other columns are NULL */
sqlite3_result_null( ctx );
}
return SQLITE_OK;
}
 
/*
** The rowid.
*/
static int fuzzerRowid( sqlite3_vtab_cursor cur, out sqlite_int64 pRowid )
{
fuzzer_cursor pCur = (fuzzer_cursor)cur;
pRowid = pCur.iRowid;
return SQLITE_OK;
}
 
/*
** When the fuzzer_cursor.rLimit value is 0 or less, that is a signal
** that the cursor has nothing more to output.
*/
static int fuzzerEof( sqlite3_vtab_cursor cur )
{
fuzzer_cursor pCur = (fuzzer_cursor)cur;
return pCur.rLimit <= (fuzzer_cost)0 ? 1 : 0;
}
 
/*
** Search for terms of these forms:
**
** word MATCH $str
** distance < $value
** distance <= $value
**
** The distance< and distance<= are both treated as distance<=.
** The query plan number is as follows:
**
** 0: None of the terms above are found
** 1: There is a "word MATCH" term with $str in filter.argv[0].
** 2: There is a "distance<" term with $value in filter.argv[0].
** 3: Both "word MATCH" and "distance<" with $str in argv[0] and
** $value in argv[1].
*/
static int fuzzerBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
{
int iPlan = 0;
int iDistTerm = -1;
int i;
sqlite3_index_constraint pConstraint;
//pConstraint = pIdxInfo.aConstraint;
for ( i = 0; i < pIdxInfo.nConstraint; i++ )//, pConstraint++)
{
pConstraint = pIdxInfo.aConstraint[i];
if ( pConstraint.usable == false )
continue;
if ( ( iPlan & 1 ) == 0
&& pConstraint.iColumn == 0
&& pConstraint.op == SQLITE_INDEX_CONSTRAINT_MATCH
)
{
iPlan |= 1;
pIdxInfo.aConstraintUsage[i].argvIndex = 1;
pIdxInfo.aConstraintUsage[i].omit = true;
}
if ( ( iPlan & 2 ) == 0
&& pConstraint.iColumn == 1
&& ( pConstraint.op == SQLITE_INDEX_CONSTRAINT_LT
|| pConstraint.op == SQLITE_INDEX_CONSTRAINT_LE )
)
{
iPlan |= 2;
iDistTerm = i;
}
}
if ( iPlan == 2 )
{
pIdxInfo.aConstraintUsage[iDistTerm].argvIndex = 1;
}
else if ( iPlan == 3 )
{
pIdxInfo.aConstraintUsage[iDistTerm].argvIndex = 2;
}
pIdxInfo.idxNum = iPlan;
if ( pIdxInfo.nOrderBy == 1
&& pIdxInfo.aOrderBy[0].iColumn == 1
&& pIdxInfo.aOrderBy[0].desc == false
)
{
pIdxInfo.orderByConsumed = true;
}
pIdxInfo.estimatedCost = (double)10000;
 
return SQLITE_OK;
}
 
/*
** Disallow all attempts to DELETE or UPDATE. Only INSERTs are allowed.
**
** On an insert, the cFrom, cTo, and cost columns are used to construct
** a new rule. All other columns are ignored. The rule is ignored
** if cFrom and cTo are identical. A NULL value for cFrom or cTo is
** interpreted as an empty string. The cost must be positive.
*/
static int fuzzerUpdate(
sqlite3_vtab pVTab,
int argc,
sqlite3_value[] argv,
out sqlite_int64 pRowid
)
{
fuzzer_vtab p = (fuzzer_vtab)pVTab;
fuzzer_rule pRule;
string zFrom;
int nFrom;
string zTo;
int nTo;
fuzzer_cost rCost;
if ( argc != 7 )
{
//sqlite3_free( pVTab.zErrMsg );
pVTab.zErrMsg = sqlite3_mprintf( "cannot delete from a %s virtual table",
p.zClassName );
pRowid = 0;
return SQLITE_CONSTRAINT;
}
if ( sqlite3_value_type( argv[0] ) != SQLITE_NULL )
{
//sqlite3_free( pVTab.zErrMsg );
pVTab.zErrMsg = sqlite3_mprintf( "cannot update a %s virtual table",
p.zClassName );
pRowid = 0;
return SQLITE_CONSTRAINT;
}
zFrom = sqlite3_value_text( argv[4] );
if ( zFrom == null )
zFrom = "";
zTo = sqlite3_value_text( argv[5] );
if ( zTo == null )
zTo = "";
if ( zFrom.CompareTo( zTo ) == 0 )//strcmp(zFrom,zTo)==0 )
{
/* Silently ignore null transformations */
pRowid = 0;
return SQLITE_OK;
}
rCost = sqlite3_value_int( argv[6] );
if ( rCost <= 0 )
{
//sqlite3_free(pVTab.zErrMsg);
pVTab.zErrMsg = sqlite3_mprintf( "cost must be positive" );
pRowid = 0;
return SQLITE_CONSTRAINT;
}
nFrom = zFrom.Length;//strlen( zFrom );
nTo = zTo.Length;//strlen(zTo);
pRule = new fuzzer_rule();// sqlite3_malloc( sizeof( pRule ) + nFrom + nTo );
//if ( pRule == null )
//{
// return SQLITE_NOMEM;
//}
//pRule.zFrom = pRule.zTo[nTo + 1];
pRule.nFrom = nFrom;
pRule.zFrom = zFrom;//memcpy( pRule.zFrom, zFrom, nFrom + 1 );
pRule.zTo = zTo;//memcpy( pRule.zTo, zTo, nTo + 1 );
pRule.nTo = nTo;
pRule.rCost = rCost;
pRule.pNext = p.pNewRule;
p.pNewRule = pRule;
pRowid = 0;
return SQLITE_OK;
}
 
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
*/
static sqlite3_module fuzzerModule = new sqlite3_module(
0, /* iVersion */
fuzzerConnect,
fuzzerConnect,
fuzzerBestIndex,
fuzzerDisconnect,
fuzzerDisconnect,
fuzzerOpen, /* xOpen - open a cursor */
fuzzerClose, /* xClose - close a cursor */
fuzzerFilter, /* xFilter - configure scan constraints */
fuzzerNext, /* xNext - advance a cursor */
fuzzerEof, /* xEof - check for end of scan */
fuzzerColumn, /* xColumn - read data */
fuzzerRowid, /* xRowid - read data */
fuzzerUpdate, /* xUpdate - INSERT */
null, /* xBegin */
null, /* xSync */
null, /* xCommit */
null, /* xRollback */
null, /* xFindMethod */
null /* xRename */
);
 
#endif ///* SQLITE_OMIT_VIRTUALTABLE */
 
 
/*
** Register the fuzzer virtual table
*/
static int fuzzer_register( sqlite3 db )
{
int rc = SQLITE_OK;
#if !SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module( db, "fuzzer", fuzzerModule, null );
#endif
return rc;
}
 
#if SQLITE_TEST
//#include <tcl.h>
/*
** Decode a pointer to an sqlite3 object.
*/
//extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 *ppDb);
 
/*
** Register the echo virtual table module.
*/
static int register_fuzzer_module(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
fuzzer_register( db );
return TCL.TCL_OK;
}
 
 
/*
** Register commands with the TCL interpreter.
*/
/*
** Register commands with the TCL interpreter.
*/
public static int Sqlitetestfuzzer_Init( Tcl_Interp interp )
{
//static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
// void *clientData;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[] {
new _aObjCmd( "register_fuzzer_module", register_fuzzer_module, 0 ),
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++)
{
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, null );
}
return TCL.TCL_OK;
}
 
#endif //* SQLITE_TEST */
 
}
#endif // TCLSH
}
/trunk/testfixture/src/test_hexio_c.cs
@@ -0,0 +1,462 @@
using System.Diagnostics;
using System.IO;
using System.Text;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
 
public partial class Sqlite3
{
/*
** 2007 April 6
**
** 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.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces. This code
** implements TCL commands for reading and writing the binary
** database files and displaying the content of those files as
** hexadecimal. We could, _in theory, use the built-_in "binary"
** command of TCL to do a lot of this, but there are some issues
** with historical versions of the "binary" command. So it seems
** easier and safer to build our own mechanism.
*************************************************************************
** 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: 2011-05-19 13:26:54 ed1da510a239ea767a01dc332b667119fa3c908e
**
*************************************************************************
*/
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
//#include <assert.h>
 
 
/*
** Convert binary to hex. The input zBuf[] contains N bytes of
** binary data. zBuf[] is 2*n+1 bytes long. Overwrite zBuf[]
** with a hexadecimal representation of its original binary input.
*/
static void sqlite3TestBinToHex( byte[] zBuf, int N )
{
StringBuilder zHex = new StringBuilder( "0123456789ABCDEF" );
int i, j;
byte c;
i = N * 2;
zBuf[i--] = 0;
for ( j = N - 1; j >= 0; j-- )
{
c = zBuf[j];
zBuf[i--] = (byte)zHex[c & 0xf];
zBuf[i--] = (byte)zHex[c >> 4];
}
Debug.Assert( i == -1 );
}
 
/*
** Convert hex to binary. The input zIn[] contains N bytes of
** hexadecimal. Convert this into binary and write aOut[] with
** the binary data. Spaces _in the original input are ignored.
** Return the number of bytes of binary rendered.
*/
static int sqlite3TestHexToBin( string zIn, int N, byte[] aOut )
{
int[] aMap = new int[] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9,10, 0, 0, 0, 0, 0, 0,
0,11,12,13,14,15,16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,11,12,13,14,15,16, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
int i, j;
int hi = 1;
int c;
 
for ( i = j = 0; i < N; i++ )
{
c = aMap[zIn[i]];
if ( c == 0 )
continue;
if ( hi != 0 )
{
aOut[j] = (byte)( ( c - 1 ) << 4 );
hi = 0;
}
else
{
aOut[j++] |= (byte)( c - 1 );
hi = 1;
}
}
return j;
}
 
 
/*
** Usage: hexio_read FILENAME OFFSET AMT
**
** Read AMT bytes from file FILENAME beginning at OFFSET from the
** beginning of the file. Convert that information to hexadecimal
** and return the resulting HEX string.
*/
static int hexio_read(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int offset = 0;
int amt = 0, got;
string zFile;
byte[] zBuf;
FileStream _in;
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "FILENAME OFFSET AMT" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out offset ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out amt ) )
return TCL.TCL_ERROR;
zFile = TCL.Tcl_GetString( objv[1] );
zBuf = new byte[amt * 2 + 1];// sqlite3Malloc( amt * 2 + 1 );
if ( zBuf == null )
{
return TCL.TCL_ERROR;
}
_in = new FileStream( zFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite );
//if( _in==null){
// _in = fopen(zFile, "r");
//}
if ( _in == null )
{
TCL.Tcl_AppendResult( interp, "cannot open input file ", zFile );
return TCL.TCL_ERROR;
}
_in.Seek( offset, SeekOrigin.Begin ); //fseek(_in, offset, SEEK_SET);
got = _in.Read( zBuf, 0, amt ); // got = fread( zBuf, 1, amt, _in );
_in.Flush();
_in.Close();// fclose( _in );
if ( got < 0 )
{
got = 0;
}
sqlite3TestBinToHex( zBuf, got );
TCL.Tcl_AppendResult( interp, System.Text.Encoding.UTF8.GetString( zBuf, 0, zBuf.Length ).Substring( 0, got * 2 ) );
zBuf = null;// sqlite3DbFree( db, ref zBuf );
return TCL.TCL_OK;
}
 
 
/*
** Usage: hexio_write FILENAME OFFSET DATA
**
** Write DATA into file FILENAME beginning at OFFSET from the
** beginning of the file. DATA is expressed _in hexadecimal.
*/
static int hexio_write(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int offset = 0;
int nIn = 0, nOut, written;
string zFile;
string zIn;
byte[] aOut;
FileStream _out;
 
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "FILENAME OFFSET HEXDATA" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out offset ) )
return TCL.TCL_ERROR;
zFile = TCL.Tcl_GetString( objv[1] );
zIn = TCL.Tcl_GetStringFromObj( objv[3], out nIn );
aOut = new byte[nIn / 2 + 1];//sqlite3Malloc( nIn/2 );
if ( aOut == null )
{
return TCL.TCL_ERROR;
}
nOut = sqlite3TestHexToBin( zIn, nIn, aOut );
_out = new FileStream( zFile, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite );// fopen( zFile, "r+b" );
//if( _out==0 ){
// _out = fopen(zFile, "r+");
//}
if ( _out == null )
{
TCL.Tcl_AppendResult( interp, "cannot open output file ", zFile );
return TCL.TCL_ERROR;
}
_out.Seek( offset, SeekOrigin.Begin );// fseek( _out, offset, SEEK_SET );
written = (int)_out.Position;
_out.Write( aOut, 0, nOut );// written = fwrite( aOut, 1, nOut, _out );
written = (int)_out.Position - written;
aOut = null;// sqlite3DbFree( db, ref aOut );
_out.Flush();
_out.Close();// fclose( _out );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( written ) );
return TCL.TCL_OK;
}
 
/*
** USAGE: hexio_get_int HEXDATA
**
** Interpret the HEXDATA argument as a big-endian integer. Return
** the value of that integer. HEXDATA can contain between 2 and 8
** hexadecimal digits.
*/
static int hexio_get_int(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int val;
int nIn = 0, nOut;
string zIn;
byte[] aOut;
byte[] aNum = new byte[4];
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "HEXDATA" );
return TCL.TCL_ERROR;
}
zIn = TCL.Tcl_GetStringFromObj( objv[1], out nIn );
aOut = new byte[nIn / 2];// sqlite3Malloc( nIn / 2 );
if ( aOut == null )
{
return TCL.TCL_ERROR;
}
nOut = sqlite3TestHexToBin( zIn, nIn, aOut );
if ( nOut >= 4 )
{
aNum[0] = aOut[0]; // memcpy( aNum, aOut, 4 );
aNum[1] = aOut[1];
aNum[2] = aOut[2];
aNum[3] = aOut[3];
}
else
{
//memset(aNum, 0, sizeof(aNum));
//memcpy(&aNum[4-nOut], aOut, nOut);
aNum[4 - nOut] = aOut[0];
if ( nOut > 1 )
aNum[4 - nOut + 1] = aOut[1];
if ( nOut > 2 )
aNum[4 - nOut + 2] = aOut[2];
if ( nOut > 3 )
aNum[4 - nOut + 3] = aOut[3];
}
aOut = null;// sqlite3DbFree( db, ref aOut );
val = ( aNum[0] << 24 ) | ( aNum[1] << 16 ) | ( aNum[2] << 8 ) | aNum[3];
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( val ) );
return TCL.TCL_OK;
}
 
 
/*
** USAGE: hexio_render_int16 INTEGER
**
** Render INTEGER has a 16-bit big-endian integer _in hexadecimal.
*/
static int hexio_render_int16(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int val = 0;
byte[] aNum = new byte[10];
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "INTEGER" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out val ) )
return TCL.TCL_ERROR;
aNum[0] = (byte)( val >> 8 );
aNum[1] = (byte)val;
sqlite3TestBinToHex( aNum, 2 );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewStringObj( aNum, 4 ) );
return TCL.TCL_OK;
}
 
 
/*
** USAGE: hexio_render_int32 INTEGER
**
** Render INTEGER has a 32-bit big-endian integer _in hexadecimal.
*/
static int hexio_render_int32(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int val = 0;
byte[] aNum = new byte[10];
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "INTEGER" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out val ) )
return TCL.TCL_ERROR;
aNum[0] = (byte)( val >> 24 );
aNum[1] = (byte)( val >> 16 );
aNum[2] = (byte)( val >> 8 );
aNum[3] = (byte)val;
sqlite3TestBinToHex( aNum, 4 );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewStringObj( aNum, 8 ) );
return TCL.TCL_OK;
}
 
/*
** USAGE: utf8_to_utf8 HEX
**
** The argument is a UTF8 string represented _in hexadecimal.
** The UTF8 might not be well-formed. Run this string through
** sqlite3Utf8to8() convert it back to hex and return the result.
*/
static int utf8_to_utf8(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
){
#if SQLITE_DEBUG
int n = 0;
int nOut;
string zOrig;
byte[] z;
if( objc!=2 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "HEX");
return TCL.TCL_ERROR;
}
zOrig = TCL.Tcl_GetStringFromObj(objv[1], out n);
z = new byte[2 * n + 1];//sqlite3Malloc( n + 3 );
nOut = sqlite3TestHexToBin( zOrig, n, z );
//z[n] = 0;
nOut = sqlite3Utf8To8(z);
sqlite3TestBinToHex( z, zOrig.Length );
TCL.Tcl_AppendResult(interp, Encoding.ASCII.GetString(z,0,n));
//sqlite3_free( z );
return TCL.TCL_OK;
#else
Tcl_AppendResult(interp,
"[utf8_to_utf8] unavailable - SQLITE_DEBUG not defined", 0
);
return TCL.TCL_ERROR;
#endif
}
 
 
//static int getFts3Varint(string p, sqlite_int64 *v){
// const unsigned char *q = (const unsigned char ) p;
// sqlite_uint64 x = 0, y = 1;
// while( (*q & 0x80) == 0x80 ){
// x += y * (*q++ & 0x7f);
// y <<= 7;
// }
// x += y * (*q++);
// *v = (sqlite_int64) x;
// return (int) (q - (unsigned char )p);
//}
 
 
///*
//** USAGE: read_fts3varint BLOB VARNAME
//**
//** Read a varint from the start of BLOB. Set variable VARNAME to contain
//** the interpreted value. Return the number of bytes of BLOB consumed.
//*/
//static int read_fts3varint(
// void * clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// int nBlob;
// unsigned string zBlob;
// sqlite3_int64 iVal;
// int nVal;
 
// if( objc!=3 ){
// Tcl_WrongNumArgs(interp, 1, objv, "BLOB VARNAME");
// return TCL.TCL_ERROR;
// }
// zBlob = TCL.Tcl_GetByteArrayFromObj(objv[1], &nBlob);
 
// nVal = getFts3Varint((char)zBlob, (sqlite3_int64 )(&iVal));
// Tcl_ObjSetVar2(interp, objv[2], 0, TCL.TCL_NewWideIntObj(iVal), 0);
// Tcl_SetObjResult(interp, TCL.TCL_NewIntObj(nVal));
// return TCL.TCL_OK;
//}
 
 
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetest_hexio_Init( Tcl_Interp interp )
{
//static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[] {
new _aObjCmd( "hexio_read", hexio_read ),
new _aObjCmd( "hexio_write", hexio_write ),
new _aObjCmd( "hexio_get_int", hexio_get_int ),
new _aObjCmd( "hexio_render_int16", hexio_render_int16 ),
new _aObjCmd( "hexio_render_int32", hexio_render_int32 ),
new _aObjCmd( "utf8_to_utf8", utf8_to_utf8 ),
// { "read_fts3varint", read_fts3varint },
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )
{
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName, aObjCmd[i].xProc, null, null );
}
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test_intarray_c.cs
@@ -0,0 +1,451 @@
using System.Diagnostics;
 
using u8 = System.Byte;
using u32 = System.UInt32;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using DbPage = Sqlite3.PgHdr;
using sqlite_int64 = System.Int64;
using sqlite3_int64 = System.Int64;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_CmdInfo = tcl.lang.WrappedCommand;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
using System;
using System.Text;
#endif
 
public partial class Sqlite3
{
/*
** 2009 November 10
**
** 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 implements a read-only VIRTUAL TABLE that contains the
** content of a C-language array of integer values. See the corresponding
** header file for full details.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
//#include "test_intarray.h"
//#include <string.h>
//#include <Debug.Assert.h>
 
 
/*
** Definition of the sqlite3_intarray object.
**
** The internal representation of an intarray object is subject
** to change, is not externally visible, and should be used by
** the implementation of intarray only. This object is opaque
** to users.
*/
class sqlite3_intarray : sqlite3_vtab
{
public int n; /* Number of elements in the array */
public sqlite3_int64[] a; /* Contents of the array */
public dxFree xFree;//void (*xFree)(void*); /* Function used to free a[] */
};
 
/* Objects used internally by the virtual table implementation */
//typedef struct intarray_vtab intarray_vtab;
//typedef struct intarray_cursor intarray_cursor;
 
/* A intarray table object */
class intarray_vtab : sqlite3_vtab
{
//sqlite3_vtab base; /* Base class */
public sqlite3_intarray pContent; /* Content of the integer array */
};
 
/* A intarray cursor object */
class intarray_cursor : sqlite3_vtab_cursor
{
//sqlite3_vtab_cursor base; /* Base class */
public int i; /* Current cursor position */
};
 
/*
** None of this works unless we have virtual tables.
*/
#if !SQLITE_OMIT_VIRTUALTABLE
 
/*
** Free an sqlite3_intarray object.
*/
static int intarrayFree( ref object p )
{
//if ( ( (sqlite3_intarray)p ).xFree != null )
//{
// p.xFree( ref p.a );
//}
p = null;//sqlite3_free(p);
return 0;
}
 
/*
** Table destructor for the intarray module.
*/
static int intarrayDestroy( ref object p )
{
//intarray_vtab *pVtab = (intarray_vtab*)p;
//sqlite3_free(pVtab);
p = null;
return 0;
}
 
/*
** Table constructor for the intarray module.
*/
static int intarrayCreate(
sqlite3 db, /* Database where module is created */
object pAux, /* clientdata for the module */
int argc, /* Number of arguments */
string[] argv, /* Value for all arguments */
out sqlite3_vtab ppVtab, /* Write the new virtual table object here */
out string pzErr /* Put error message text here */
)
{
int rc = SQLITE_NOMEM;
intarray_vtab pVtab = new intarray_vtab();//sqlite3_malloc(sizeof(intarray_vtab));
 
if ( pVtab != null )
{
//memset(pVtab, 0, sizeof(intarray_vtab));
pVtab.pContent = (sqlite3_intarray)pAux;
rc = sqlite3_declare_vtab( db, "CREATE TABLE x(value INTEGER PRIMARY KEY)" );
}
ppVtab = (sqlite3_vtab)pVtab;
pzErr = "";
return rc;
}
 
/*
** Open a new cursor on the intarray table.
*/
static int intarrayOpen( sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor )
{
int rc = SQLITE_NOMEM;
intarray_cursor pCur = new intarray_cursor();//
//pCur = sqlite3_malloc(sizeof(intarray_cursor));
//if ( pCur != null )
{
//memset(pCur, 0, sizeof(intarray_cursor));
ppCursor = (sqlite3_vtab_cursor)pCur;
rc = SQLITE_OK;
}
return rc;
}
 
/*
** Close a intarray table cursor.
*/
static int intarrayClose( ref sqlite3_vtab_cursor cur )
{
//intarray_cursor *pCur = (intarray_cursor *)cur;
//sqlite3_free(pCur);
cur = null;
return SQLITE_OK;
}
 
/*
** Retrieve a column of data.
*/
static int intarrayColumn( sqlite3_vtab_cursor cur, sqlite3_context ctx, int i )
{
intarray_cursor pCur = (intarray_cursor)cur;
intarray_vtab pVtab = (intarray_vtab)cur.pVtab;
if ( pCur.i >= 0 && pCur.i < pVtab.pContent.n )
{
sqlite3_result_int64( ctx, pVtab.pContent.a[pCur.i] );
}
return SQLITE_OK;
}
 
/*
** Retrieve the current rowid.
*/
static int intarrayRowid( sqlite3_vtab_cursor cur, out sqlite_int64 pRowid )
{
intarray_cursor pCur = (intarray_cursor)cur;
pRowid = pCur.i;
return SQLITE_OK;
}
 
static int intarrayEof( sqlite3_vtab_cursor cur )
{
intarray_cursor pCur = (intarray_cursor)cur;
intarray_vtab pVtab = (intarray_vtab)cur.pVtab;
return pCur.i >= pVtab.pContent.n ? 1 : 0;
}
 
/*
** Advance the cursor to the next row.
*/
static int intarrayNext( sqlite3_vtab_cursor cur )
{
intarray_cursor pCur = (intarray_cursor)cur;
pCur.i++;
return SQLITE_OK;
}
 
/*
** Reset a intarray table cursor.
*/
static int intarrayFilter(
sqlite3_vtab_cursor pVtabCursor,
int idxNum, string idxStr,
int argc, sqlite3_value[] argv
)
{
intarray_cursor pCur = (intarray_cursor)pVtabCursor;
pCur.i = 0;
return SQLITE_OK;
}
 
/*
** Analyse the WHERE condition.
*/
static int intarrayBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
{
return SQLITE_OK;
}
 
/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/
static sqlite3_module intarrayModule = new sqlite3_module(
0, /* iVersion */
intarrayCreate, /* xCreate - create a new virtual table */
intarrayCreate, /* xConnect - connect to an existing vtab */
intarrayBestIndex, /* xBestIndex - find the best query index */
intarrayDestroy, /* xDisconnect - disconnect a vtab */
intarrayDestroy, /* xDestroy - destroy a vtab */
intarrayOpen, /* xOpen - open a cursor */
intarrayClose, /* xClose - close a cursor */
intarrayFilter, /* xFilter - configure scan constraints */
intarrayNext, /* xNext - advance a cursor */
intarrayEof, /* xEof */
intarrayColumn, /* xColumn - read data */
intarrayRowid, /* xRowid - read data */
null, /* xUpdate */
null, /* xBegin */
null, /* xSync */
null, /* xCommit */
null, /* xRollback */
null, /* xFindMethod */
null /* xRename */
);
 
#endif //* !defined(SQLITE_OMIT_VIRTUALTABLE) */
 
/*
** Invoke this routine to create a specific instance of an intarray object.
** The new intarray object is returned by the 3rd parameter.
**
** Each intarray object corresponds to a virtual table in the TEMP table
** with a name of zName.
**
** Destroy the intarray object by dropping the virtual table. If not done
** explicitly by the application, the virtual table will be dropped implicitly
** by the system when the database connection is closed.
*/
static int sqlite3_intarray_create(
sqlite3 db,
string zName,
out sqlite3_intarray ppReturn
)
{
int rc = SQLITE_OK;
#if !SQLITE_OMIT_VIRTUALTABLE
sqlite3_intarray p;
 
ppReturn = p = new sqlite3_intarray();//sqlite3_malloc( sizeof(*p) );
//if( p==0 ){
// return SQLITE_NOMEM;
//}
//memset(p, 0, sizeof(*p));
rc = sqlite3_create_module_v2( db, zName, intarrayModule, p,
intarrayFree );
if ( rc == SQLITE_OK )
{
string zSql;
zSql = sqlite3_mprintf( "CREATE VIRTUAL TABLE temp.%Q USING %Q",
zName, zName );
rc = sqlite3_exec( db, zSql, 0, 0, 0 );
//sqlite3_free(zSql);
}
#endif
return rc;
}
 
/*
** Bind a new array array of integers to a specific intarray object.
**
** The array of integers bound must be unchanged for the duration of
** any query against the corresponding virtual table. If the integer
** array does change or is deallocated undefined behavior will result.
*/
static int sqlite3_intarray_bind(
sqlite3_intarray pIntArray, /* The intarray object to bind to */
int nElements, /* Number of elements in the intarray */
sqlite3_int64[] aElements, /* Content of the intarray */
dxFree xFree//void (*xFree)(void*) /* How to dispose of the intarray when done */
)
{
if ( pIntArray.xFree != null )
{
pIntArray.a = null;//pIntArray.xFree( pIntArray.a );
}
pIntArray.n = nElements;
pIntArray.a = aElements;
pIntArray.xFree = xFree;
return SQLITE_OK;
}
 
 
/*****************************************************************************
** Everything below is interface for testing this module.
*/
#if SQLITE_TEST
//#include <tcl.h>
 
/*
** Routines to encode and decode pointers
*/
//extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
//extern void *sqlite3TestTextToPtr(const char*);
//extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*);
//extern const char *sqlite3TestErrorName(int);
 
/*
** sqlite3_intarray_create DB NAME
**
** Invoke the sqlite3_intarray_create interface. A string that becomes
** the first parameter to sqlite3_intarray_bind.
*/
static int test_intarray_create(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db;
string zName;
sqlite3_intarray pArray;
int rc = SQLITE_OK;
StringBuilder zPtr = new StringBuilder( 100 );
 
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
zName = TCL.Tcl_GetString( objv[2] );
#if !SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_intarray_create( db, zName, out pArray );
#endif
if ( rc != SQLITE_OK )
{
Debug.Assert( pArray == null );
TCL.Tcl_AppendResult( interp, sqlite3TestErrorName( rc ), null );
return TCL.TCL_ERROR;
}
sqlite3TestMakePointerStr( interp, zPtr, pArray );
TCL.Tcl_AppendResult( interp, zPtr, null );
return TCL.TCL_OK;
}
 
/*
** sqlite3_intarray_bind INTARRAY ?VALUE ...?
**
** Invoke the sqlite3_intarray_bind interface on the given array of integers.
*/
static int test_intarray_bind(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3_intarray pArray;
int rc = SQLITE_OK;
int i, n;
sqlite3_int64[] a;
 
if ( objc < 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "INTARRAY" );
return TCL.TCL_ERROR;
}
pArray = (sqlite3_intarray)sqlite3TestTextToPtr( interp, TCL.Tcl_GetString( objv[1] ) );
n = objc - 2;
#if !SQLITE_OMIT_VIRTUALTABLE
a = new sqlite3_int64[n];//sqlite3_malloc( sizeof(a[0])*n );
//if( a==0 ){
// Tcl_AppendResult(interp, "SQLITE_NOMEM", (char*)0);
// return TCL_ERROR;
//}
for ( i = 0; i < n; i++ )
{
//a[i] = 0;
TCL.Tcl_GetWideIntFromObj( null, objv[i + 2], out a[i] );
}
rc = sqlite3_intarray_bind( pArray, n, a, sqlite3_free );
if ( rc != SQLITE_OK )
{
TCL.Tcl_AppendResult( interp, sqlite3TestErrorName( rc ), null );
return TCL.TCL_ERROR;
}
#endif
return TCL.TCL_OK;
}
 
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetestintarray_Init( Tcl_Interp interp )
{
//static struct {
// char *zName;
// Tcl_ObjCmdProc *xProc;
// void *clientData;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[] {
new _aObjCmd( "sqlite3_intarray_create", test_intarray_create, 0 ),
new _aObjCmd( "sqlite3_intarray_bind", test_intarray_bind, 0 ),
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++)
{
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, null );
}
return TCL.TCL_OK;
}
 
#endif //* SQLITE_TEST */
}
}
/trunk/testfixture/src/test_malloc_c.cs
@@ -0,0 +1,1637 @@
using System.Diagnostics;
 
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
 
public partial class Sqlite3
{
 
/*
** 2007 August 15
**
** 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 used to implement test interfaces to the
** memory allocation subsystem.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
//#include <assert.h>
 
/*
** This structure is used to encapsulate the global state variables used
** by malloc() fault simulation.
*/
struct MemFault
{
public int iCountdown; /* Number of pending successes before a failure */
public int nRepeat; /* Number of times to repeat the failure */
public int nBenign; /* Number of benign failures seen since last config */
public int nFail; /* Number of failures seen since last config */
public int enable; /* True if enabled */
public int isInstalled; /* True if the fault simulation layer is installed */
public int isBenignMode; /* True if malloc failures are considered benign */
public sqlite3_mem_methods m; /* 'Real' malloc implementation */
}
static MemFault memfault;
 
/*
** This routine exists as a place to set a breakpoint that will
** fire on any simulated malloc() failure.
*/
static int cnt = 0;
static void sqlite3Fault()
{
cnt++;
}
 
/*
** Check to see if a fault should be simulated. Return true to simulate
** the fault. Return false if the fault should not be simulated.
*/
static int faultsimStep()
{
if ( likely( memfault.enable != 0 ) )
{
return 0;
}
if ( memfault.iCountdown > 0 )
{
memfault.iCountdown--;
return 0;
}
sqlite3Fault();
memfault.nFail++;
if ( memfault.isBenignMode > 0 )
{
memfault.nBenign++;
}
memfault.nRepeat--;
if ( memfault.nRepeat <= 0 )
{
memfault.enable = 0;
}
return 1;
}
 
/*
** A version of sqlite3_mem_methods.xMalloc() that includes fault simulation
** logic.
*/
static byte[] faultsimMalloc( int n )
{
byte[] p = null;
if ( faultsimStep() != 0 )
{
p = memfault.m.xMalloc( n );
}
return p;
}
static int[] faultsimMallocInt( int n )
{
int[] p = null;
if ( faultsimStep() != 0 )
{
p = memfault.m.xMallocInt( n );
}
return p;
}
static Mem faultsimMallocMem( Mem n )
{
Mem p = null;
if ( faultsimStep() != 0 )
{
p = memfault.m.xMallocMem( n );
}
return p;
}
/*
** A version of sqlite3_mem_methods.xRealloc() that includes fault simulation
** logic.
*/
static byte[] faultsimRealloc( byte[] pOld, int n )
{
byte[] p = null;
if ( faultsimStep() != 0 )
{
p = memfault.m.xRealloc( pOld, n );
}
return p;
}
 
/*
** The following method calls are passed directly through to the underlying
** malloc system:
**
** xFree
** xSize
** xRoundup
** xInit
** xShutdown
*/
static void faultsimFree( ref byte[] p )
{
memfault.m.xFree( ref p );
}
static void faultsimFreeInt( ref int[] p )
{
memfault.m.xFreeInt( ref p );
}
static void faultsimFreeMem( ref Mem p )
{
memfault.m.xFreeMem( ref p );
}
static int faultsimSize( byte[] p )
{
return memfault.m.xSize( p );
}
static int faultsimRoundup( int n )
{
return memfault.m.xRoundup( n );
}
static int faultsimInit( object p )
{
return memfault.m.xInit( memfault.m.pAppData );
}
static void faultsimShutdown( object p )
{
memfault.m.xShutdown( memfault.m.pAppData );
}
 
/*
** This routine configures the malloc failure simulation. After
** calling this routine, the next nDelay mallocs will succeed, followed
** by a block of nRepeat failures, after which malloc() calls will begin
** to succeed again.
*/
static void faultsimConfig( int nDelay, int nRepeat )
{
memfault.iCountdown = nDelay;
memfault.nRepeat = nRepeat;
memfault.nBenign = 0;
memfault.nFail = 0;
memfault.enable = ( nDelay >= 0 ) ? 1 : 0;
 
/* Sometimes, when running multi-threaded tests, the isBenignMode
** variable is not properly incremented/decremented so that it is
** 0 when not inside a benign malloc block. This doesn't affect
** the multi-threaded tests, as they do not use this system. But
** it does affect OOM tests run later in the same process. So
** zero the variable here, just to be sure.
*/
memfault.isBenignMode = 0;
}
 
/*
** Return the number of faults (both hard and benign faults) that have
** occurred since the injector was last configured.
*/
static int faultsimFailures()
{
return memfault.nFail;
}
 
/*
** Return the number of benign faults that have occurred since the
** injector was last configured.
*/
static int faultsimBenignFailures()
{
return memfault.nBenign;
}
 
/*
** Return the number of successes that will occur before the next failure.
** If no failures are scheduled, return -1.
*/
static int faultsimPending()
{
if ( memfault.enable != 0 )
{
return memfault.iCountdown;
}
else
{
return -1;
}
}
 
 
static void faultsimBeginBenign()
{
memfault.isBenignMode++;
}
static void faultsimEndBenign()
{
memfault.isBenignMode--;
}
 
/*
** Add or remove the fault-simulation layer using sqlite3_config(). If
** the argument is non-zero, the
*/
static int faultsimInstall( int install )
{
sqlite3_mem_methods m = new sqlite3_mem_methods(
(dxMalloc)faultsimMalloc, /* xMalloc */
(dxMallocInt)faultsimMallocInt, /* xMalloc */
(dxMallocMem)faultsimMallocMem, /* xMalloc */
(dxFree)faultsimFree, /* xFree */
(dxFreeInt)faultsimFreeInt, /* xFree */
(dxFreeMem)faultsimFreeMem,
(dxRealloc)faultsimRealloc, /* xRealloc */
(dxSize)faultsimSize, /* xSize */
(dxRoundup)faultsimRoundup, /* xRoundup */
(dxMemInit)faultsimInit, /* xInit */
(dxMemShutdown)faultsimShutdown, /* xShutdown */
null /* pAppData */
);
int rc;
 
//install = ( install != 0 ? 1 : 0 );
Debug.Assert( memfault.isInstalled == 1 || memfault.isInstalled == 0 );
 
if ( install == memfault.isInstalled )
{
return SQLITE_ERROR;
}
 
if ( install != 0 )
{
rc = sqlite3_config( SQLITE_CONFIG_GETMALLOC, ref memfault.m );
Debug.Assert( memfault.m.xMalloc != null );
if ( rc == SQLITE_OK )
{
rc = sqlite3_config( SQLITE_CONFIG_MALLOC, m );
}
sqlite3_test_control( SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS,
(void_function)faultsimBeginBenign, (void_function)faultsimEndBenign
);
}
else
{
//sqlite3_mem_methods m;
Debug.Assert( memfault.m.xMalloc != null );
 
/* One should be able to reset the default memory allocator by storing
** a zeroed allocator then calling GETMALLOC. */
m = new sqlite3_mem_methods();// memset( &m, 0, sizeof( m ) );
sqlite3_config( SQLITE_CONFIG_MALLOC, m );
sqlite3_config( SQLITE_CONFIG_GETMALLOC, ref m );
Debug.Assert( m.GetHashCode() == memfault.m.GetHashCode() );//memcmp(&m, &memfault.m, sizeof(m))==0 );
 
rc = sqlite3_config( SQLITE_CONFIG_MALLOC, ref memfault.m );
sqlite3_test_control( SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, 0, 0 );
}
 
if ( rc == SQLITE_OK )
{
memfault.isInstalled = 1;
}
return rc;
}
 
#if SQLITE_TEST
 
/*
** This function is implemented in test1.c. Returns a pointer to a static
** buffer containing the symbolic SQLite error code that corresponds to
** the least-significant 8-bits of the integer passed as an argument.
** For example:
**
** sqlite3TestErrorName(1) -> "SQLITE_ERROR"
*/
//string sqlite3TestErrorName(int);
 
 
/*
** Transform pointers to text and back again
*/
//static void pointerToText(object p, string z){
// static const char zHex[] = "0123456789abcdef";
// int i, k;
// unsigned int u;
// sqlite3_u3264 n;
// if( p==0 ){
// strcpy(z, "0");
// return;
//}
// if( sizeof(n)==sizeof(p) ){
// memcpy(&n, ref p, sizeof(p));
// }else if( sizeof(u)==sizeof(p) ){
// memcpy(&u, ref p, sizeof(u));
// n = u;
// }else{
// Debug.Assert( 0 );
// }
// for(i=0, k=sizeof(p)*2-1; i<sizeof(p)*2; i++, k--){
// z[k] = zHex[n&0xf];
// n >>= 4;
// }
// z[sizeof(p)*2] = 0;
//}
//static int hexToInt(int h){
// if( h>='0' && h<='9' ){
// return h - '0';
// }else if( h>='a' && h<='f' ){
// return h - 'a' + 10;
// }else{
// return -1;
// }
//}
//static int textToPointer(string z, object **pp){
// sqlite3_u3264 n = 0;
// int i;
// unsigned int u;
// for(i=0; i<sizeof(void)*2 && z[0]; i++){
// int v;
// v = hexToInt(*z++);
// if( v<0 ) return TCL.TCL_ERROR;
// n = n*16 + v;
// }
// if( *z!=0 ) return TCL.TCL_ERROR;
// if( sizeof(n)==sizeof(*pp) ){
// memcpy(pp, ref n, sizeof(n));
// }else if( sizeof(u)==sizeof(*pp) ){
// u = (unsigned int)n;
// memcpy(pp, ref u, sizeof(u));
// }else{
// Debug.Assert( 0 );
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3Malloc NBYTES
**
** Raw test interface for sqlite3Malloc().
*/
//static int test_malloc(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// int nByte;
// object p;
// char zOut[100];
// if( objc!=2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "NBYTES");
// return TCL.TCL_ERROR;
// }
// if( TCL.Tcl_GetIntFromObj(interp, objv[1], out nByte) ) return TCL.TCL_ERROR;
// p = sqlite3Malloc((unsigned)nByte);
// pointerToText(p, zOut);
// TCL.TCL_AppendResult(interp, zOut, NULL);
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_realloc PRIOR NBYTES
**
** Raw test interface for sqlite3_realloc().
*/
//static int test_realloc(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// int nByte;
// void pPrior, p;
// char zOut[100];
// if( objc!=3 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "PRIOR NBYTES");
// return TCL.TCL_ERROR;
// }
// if( TCL.Tcl_GetIntFromObj(interp, objv[2], out nByte) ) return TCL.TCL_ERROR;
// if( textToPointer(Tcl_GetString(objv[1]), out pPrior) ){
// TCL.TCL_AppendResult(interp, "bad pointer: ", TCL.Tcl_GetString(objv[1]));
// return TCL.TCL_ERROR;
// }
// p = sqlite3_realloc(pPrior, (unsigned)nByte);
// pointerToText(p, zOut);
// TCL.TCL_AppendResult(interp, zOut, NULL);
// return TCL.TCL_OK;
//}
 
/*
** tclcmd: sqlite3_config_uri BOOLEAN
**
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
** opcodes and verify that they return errors.
*/
static int test_config_uri(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
){
int rc;
bool bOpenUri = false;
 
if( objc!=2 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[1], out bOpenUri ) )
{
return TCL.TCL_ERROR;
}
 
rc = sqlite3_config(SQLITE_CONFIG_URI, bOpenUri);
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE );
 
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_free PRIOR
**
** Raw test interface for sqlite3DbFree(db,).
*/
//static int test_free(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// void pPrior;
// if( objc!=2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "PRIOR");
// return TCL.TCL_ERROR;
// }
// if( textToPointer(Tcl_GetString(objv[1]), out pPrior) ){
// TCL.TCL_AppendResult(interp, "bad pointer: ", TCL.Tcl_GetString(objv[1]));
// return TCL.TCL_ERROR;
// }
// sqlite3DbFree(db,pPrior);
// return TCL.TCL_OK;
//}
 
/*
** These routines are in test_hexio.c
*/
//int sqlite3TestHexToBin(string , int, char );
//int sqlite3TestBinToHex(char*,int);
 
/*
** Usage: memset ADDRESS SIZE HEX
**
** Set a chunk of memory (obtained from malloc, probably) to a
** specified hex pattern.
*/
//static int test_memset(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// object p;
// int size, n, i;
// string zHex;
// string zOut;
// char zBin[100];
 
// if( objc!=4 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE HEX");
// return TCL.TCL_ERROR;
// }
// if( textToPointer(Tcl_GetString(objv[1]), out p) ){
// TCL.TCL_AppendResult(interp, "bad pointer: ", TCL.Tcl_GetString(objv[1]));
// return TCL.TCL_ERROR;
// }
// if( TCL.Tcl_GetIntFromObj(interp, objv[2], out size) ){
// return TCL.TCL_ERROR;
// }
// if( size<=0 ){
// TCL.TCL_AppendResult(interp, "size must be positive");
// return TCL.TCL_ERROR;
// }
// zHex = TCL.Tcl_GetStringFromObj(objv[3], out n);
// if( n>sizeof(zBin)*2 ) n = sizeof(zBin)*2;
// n = sqlite3TestHexToBin(zHex, n, zBin);
// if( n==0 ){
// TCL.TCL_AppendResult(interp, "no data");
// return TCL.TCL_ERROR;
// }
// zOut = p;
// for(i=0; i<size; i++){
// zOut[i] = zBin[i%n];
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: memget ADDRESS SIZE
**
** Return memory as hexadecimal text.
*/
//static int test_memget(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// object p;
// int size, n;
// string zBin;
// char zHex[100];
 
// if( objc!=3 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "ADDRESS SIZE");
// return TCL.TCL_ERROR;
// }
// if( textToPointer(Tcl_GetString(objv[1]), out p) ){
// TCL.TCL_AppendResult(interp, "bad pointer: ", TCL.Tcl_GetString(objv[1]));
// return TCL.TCL_ERROR;
// }
// if( TCL.Tcl_GetIntFromObj(interp, objv[2], out size) ){
// return TCL.TCL_ERROR;
// }
// if( size<=0 ){
// TCL.TCL_AppendResult(interp, "size must be positive");
// return TCL.TCL_ERROR;
// }
// zBin = p;
// while( size>0 ){
// if( size>(sizeof(zHex)-1)/2 ){
// n = (sizeof(zHex)-1)/2;
// }else{
// n = size;
// }
// memcpy(zHex, zBin, n);
// zBin += n;
// size -= n;
// sqlite3TestBinToHex(zHex, n);
// TCL.TCL_AppendResult(interp, zHex);
// }
// return TCL.TCL_OK;
//}
#if FALSE
/*
** Usage: sqlite3_memory_used
**
** Raw test interface for sqlite3_memory_used().
*/
static int test_memory_used(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewWideIntObj( sqlite3_memory_used() ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_memory_highwater ?RESETFLAG?
**
** Raw test interface for sqlite3_memory_highwater().
*/
static int test_memory_highwater(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
bool resetFlag = false;
if ( objc != 1 && objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "?RESET?" );
return TCL.TCL_ERROR;
}
if ( objc == 2 )
{
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[1], out resetFlag ) ) return TCL.TCL_ERROR;
}
TCL.Tcl_SetObjResult( interp,
TCL.Tcl_NewWideIntObj( sqlite3_memory_highwater( resetFlag ? 1 : 0 ) ) );
return TCL.TCL_OK;
}
#endif
 
/*
** Usage: sqlite3_memdebug_backtrace DEPTH
**
** Set the depth of backtracing. If SQLITE_MEMDEBUG is not defined
** then this routine is a no-op.
*/
//static int test_memdebug_backtrace(
// object clientdata,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// int depth;
// if( objc!=2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "DEPT");
// return TCL.TCL_ERROR;
// }
// if( TCL.Tcl_GetIntFromObj(interp, objv[1], out depth) ) return TCL.TCL_ERROR;
//#if SQLITE_MEMDEBUG
// {
// extern void sqlite3MemdebugBacktrace(int);
// sqlite3MemdebugBacktrace(depth);
// }
//#endif
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_memdebug_dump FILENAME
**
** Write a summary of unfreed memory to FILENAME.
*/
static int test_memdebug_dump(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "FILENAME" );
return TCL.TCL_ERROR;
}
#if (SQLITE_MEMDEBUG) || (SQLITE_MEMORY_SIZE) || (SQLITE_POW2_MEMORY_SIZE)
{
extern void sqlite3MemdebugDump(const char);
sqlite3MemdebugDump(Tcl_GetString(objv[1]));
}
#endif
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_memdebug_malloc_count
**
** Return the total number of times malloc() has been called.
*/
static int test_memdebug_malloc_count(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int nMalloc = -1;
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
#if SQLITE_MEMDEBUG
{
extern int sqlite3MemdebugMallocCount();
nMalloc = sqlite3MemdebugMallocCount();
}
#endif
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( nMalloc ) );
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS?
**
** where options are:
**
** -repeat <count>
** -benigncnt <varname>
**
** Arrange for a simulated malloc() failure after COUNTER successes.
** If a repeat count is specified, the fault is repeated that many
** times.
**
** Each call to this routine overrides the prior counter value.
** This routine returns the number of simulated failures that have
** happened since the previous call to this routine.
**
** To disable simulated failures, use a COUNTER of -1.
*/
static int test_memdebug_fail(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int ii;
int iFail = 0;
int nRepeat = 1;
Tcl_Obj pBenignCnt = null;
int nBenign;
int nFail = 0;
 
if ( objc < 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "COUNTER ?OPTIONS?" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out iFail ) )
return TCL.TCL_ERROR;
 
for ( ii = 2; ii < objc; ii += 2 )
{
int nOption = 0;
string zOption = TCL.Tcl_GetStringFromObj( objv[ii], out nOption );
string zErr = "";
 
if ( nOption > 1 && zOption == "-repeat" )
{
if ( ii == ( objc - 1 ) )
{
zErr = "option requires an argument: ";
}
else
{
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[ii + 1], out nRepeat ) )
{
return TCL.TCL_ERROR;
}
}
}
else if ( nOption > 1 && zOption == "-benigncnt" )
{
if ( ii == ( objc - 1 ) )
{
zErr = "option requires an argument: ";
}
else
{
pBenignCnt = objv[ii + 1];
}
}
else
{
zErr = "unknown option: ";
}
 
if ( zErr != "" )
{
TCL.Tcl_AppendResult( interp, zErr, zOption );
return TCL.TCL_ERROR;
}
}
 
nBenign = faultsimBenignFailures();
nFail = faultsimFailures();
faultsimConfig( iFail, nRepeat );
if ( pBenignCnt != null )
{
TCL.Tcl_ObjSetVar2( interp, pBenignCnt, null, TCL.Tcl_NewIntObj( nBenign ), 0 );
}
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( nFail ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_memdebug_pending
**
** Return the number of malloc() calls that will succeed before a
** simulated failure occurs. A negative return value indicates that
** no malloc() failure is scheduled.
*/
// static int test_memdebug_pending(
// object clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// int nPending;
// if( objc!=1 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "");
// return TCL.TCL_ERROR;
// }
// nPending = faultsimPending();
// TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(nPending));
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_memdebug_settitle TITLE
**
** Set a title string stored with each allocation. The TITLE is
** typically the name of the test that was running when the
** allocation occurred. The TITLE is stored with the allocation
** and can be used to figure out which tests are leaking memory.
**
** Each title overwrite the previous.
*/
static int test_memdebug_settitle(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
string zTitle;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "TITLE" );
return TCL.TCL_ERROR;
}
zTitle = TCL.Tcl_GetString( objv[1] );
#if SQLITE_MEMDEBUG
{
extern int sqlite3MemdebugSettitle(const char);
sqlite3MemdebugSettitle(zTitle);
}
#endif
return TCL.TCL_OK;
}
 
//#define MALLOC_LOG_FRAMES 10
//static TCL.Tcl_HashTable aMallocLog;
//static int mallocLogEnabled = 0;
 
//typedef struct MallocLog MallocLog;
//struct MallocLog {
// int nCall;
// int nByte;
//};
 
//#if SQLITE_MEMDEBUG
//static void test_memdebug_callback(int nByte, int nFrame, object **aFrame){
// if( mallocLogEnabled ){
// MallocLog pLog;
// TCL.Tcl_HashEntry pEntry;
// int isNew;
 
// int aKey[MALLOC_LOG_FRAMES];
// int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
 
// memset(aKey, 0, nKey);
// if( (sizeof(void)*nFrame)<nKey ){
// nKey = nFrame*sizeof(void);
// }
// memcpy(aKey, aFrame, nKey);
 
// pEntry = TCL.Tcl_CreateHashEntry(&aMallocLog, (string )aKey, ref isNew);
// if( isNew ){
// pLog = (MallocLog )Tcl_Alloc(sizeof(MallocLog));
// memset(pLog, 0, sizeof(MallocLog));
// TCL.Tcl_SetHashValue(pEntry, (ClientData)pLog);
// }else{
// pLog = (MallocLog )Tcl_GetHashValue(pEntry);
// }
 
// pLog->nCall++;
// pLog->nByte += nByte;
// }
//}
//#endif //* SQLITE_MEMDEBUG */
 
//static void test_memdebug_log_clear(){
// TCL.Tcl_HashSearch search;
// TCL.Tcl_HashEntry pEntry;
// for(
// pEntry=Tcl_FirstHashEntry(&aMallocLog, ref search);
// pEntry;
// pEntry=Tcl_NextHashEntry(&search)
// ){
// MallocLog pLog = (MallocLog )Tcl_GetHashValue(pEntry);
// TCL.Tcl_Free((char )pLog);
// }
// TCL.Tcl_DeleteHashTable(&aMallocLog);
// TCL.Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
//}
 
//static int test_memdebug_log(
// object clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// static int isInit = 0;
// int iSub;
 
// static string MB_strs[] = { "start", "stop", "dump", "clear", "sync" };
// enum MB_enum {
// MB_LOG_START, MB_LOG_STOP, MB_LOG_DUMP, MB_LOG_CLEAR, MB_LOG_SYNC
// };
 
// if( null==isInit ){
//#if SQLITE_MEMDEBUG
// extern void sqlite3MemdebugBacktraceCallback(
// void (*xBacktrace)(int, int, object *));
// sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
//#endif
// TCL.Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
// isInit = 1;
// }
 
// if( objc<2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
// }
// if( TCL.Tcl_GetIndexFromObj(interp, objv[1], MB_strs, "sub-command", 0, out iSub) ){
// return TCL.TCL_ERROR;
// }
 
// switch( (enum MB_enum)iSub ){
// case MB_LOG_START:
// mallocLogEnabled = 1;
// break;
// case MB_LOG_STOP:
// mallocLogEnabled = 0;
// break;
// case MB_LOG_DUMP: {
// TCL.Tcl_HashSearch search;
// TCL.Tcl_HashEntry pEntry;
// Tcl_Obj pRet = TCL.Tcl_NewObj();
 
// Debug.Assert(sizeof(int)==sizeof(void));
 
// for(
// pEntry=Tcl_FirstHashEntry(&aMallocLog, ref search);
// pEntry;
// pEntry=Tcl_NextHashEntry(&search)
// ){
// Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
// MallocLog pLog = (MallocLog )Tcl_GetHashValue(pEntry);
// int *aKey = (int )Tcl_GetHashKey(&aMallocLog, pEntry);
// int ii;
 
// apElem[0] = TCL.Tcl_NewIntObj(pLog->nCall);
// apElem[1] = TCL.Tcl_NewIntObj(pLog->nByte);
// for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
// apElem[ii+2] = TCL.Tcl_NewIntObj(aKey[ii]);
// }
 
// TCL.Tcl_ListObjAppendElement(interp, pRet,
// TCL.Tcl_NewListObj(MALLOC_LOG_FRAMES+2, apElem)
// );
// }
 
// TCL.Tcl_SetObjResult(interp, pRet);
// break;
// }
// case MB_LOG_CLEAR: {
// test_memdebug_log_clear();
// break;
// }
 
// case MB_LOG_SYNC: {
//#if SQLITE_MEMDEBUG
// extern void sqlite3MemdebugSync();
// test_memdebug_log_clear();
// mallocLogEnabled = 1;
// sqlite3MemdebugSync();
//#endif
// break;
// }
// }
 
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_config_scratch SIZE N
**
** Set the scratch memory buffer using SQLITE_CONFIG_SCRATCH.
** The buffer is static and is of limited size. N might be
** adjusted downward as needed to accomodate the requested size.
** The revised value of N is returned.
**
** A negative SIZE causes the buffer pointer to be NULL.
*/
static int test_config_scratch(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int sz = 0, N = 0, rc;
Tcl_Obj pResult;
byte[][] buf = null;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SIZE N" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out sz ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out N ) )
return TCL.TCL_ERROR;
//free(buf);
if ( sz < 0 )
{
buf = null;
rc = sqlite3_config( SQLITE_CONFIG_SCRATCH, 0, 0, 0 );
}
else
{
buf = new byte[2][];//// malloc( sz * N + 1 );
rc = sqlite3_config( SQLITE_CONFIG_SCRATCH, buf, sz, N );
}
pResult = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( rc ) );
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( N ) );
TCL.Tcl_SetObjResult( interp, pResult );
return TCL.TCL_OK;
}
 
 
/*
** Usage: sqlite3_config_pagecache SIZE N
**
** Set the page-cache memory buffer using SQLITE_CONFIG_PAGECACHE.
** The buffer is static and is of limited size. N might be
** adjusted downward as needed to accomodate the requested size.
** The revised value of N is returned.
**
** A negative SIZE causes the buffer pointer to be NULL.
*/
static int test_config_pagecache(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int sz = 0, N = 0, rc;
Tcl_Obj pResult;
MemPage buf; // byte[] buf = null;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SIZE N" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out sz ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out N ) )
return TCL.TCL_ERROR;
//free(buf);
if ( sz < 0 )
{
buf = null;
rc = sqlite3_config( SQLITE_CONFIG_PAGECACHE, 0, 0, 0 );
}
else
{
buf = new MemPage();// new byte[sz * N]; //malloc( sz * N );
rc = sqlite3_config( SQLITE_CONFIG_PAGECACHE, buf, sz, N );
}
pResult = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( rc ) );
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( N ) );
TCL.Tcl_SetObjResult( interp, pResult );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_config_alt_pcache INSTALL_FLAG DISCARD_CHANCE PRNG_SEED
**
** Set up the alternative test page cache. Install if INSTALL_FLAG is
** true and uninstall (reverting to the default page cache) if INSTALL_FLAG
** is false. DISCARD_CHANGE is an integer between 0 and 100 inclusive
** which determines the chance of discarding a page when unpinned. 100
** is certainty. 0 is never. PRNG_SEED is the pseudo-random number generator
** seed.
*/
//static int test_alt_pcache(
// object clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// int installFlag;
// int discardChance = 0;
// int prngSeed = 0;
// int highStress = 0;
// extern void installTestPCache(int,unsigned,unsigned,unsigned);
// if( objc<2 || objc>5 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv,
// "INSTALLFLAG DISCARDCHANCE PRNGSEEED HIGHSTRESS");
// return TCL.TCL_ERROR;
// }
// if( TCL.Tcl_GetIntFromObj(interp, objv[1], &installFlag) ) return TCL.TCL_ERROR;
// if( objc>=3 && TCL.Tcl_GetIntFromObj(interp, objv[2], &discardChance) ){
// return TCL.TCL_ERROR;
// }
// if( objc>=4 && TCL.Tcl_GetIntFromObj(interp, objv[3], &prngSeed) ){
// return TCL.TCL_ERROR;
// }
// if( objc>=5 && TCL.Tcl_GetIntFromObj(interp, objv[4], &highStress) ){
// return TCL.TCL_ERROR;
// }
// if( discardChance<0 || discardChance>100 ){
// TCL.Tcl_AppendResult(interp, "discard-chance should be between 0 and 100",
// (char)0);
// return TCL.TCL_ERROR;
// }
// installTestPCache(installFlag, (unsigned)discardChance, (unsigned)prngSeed,
// (unsigned)highStress);
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_config_memstatus BOOLEAN
**
** Enable or disable memory status reporting using SQLITE_CONFIG_MEMSTATUS.
*/
static int test_config_memstatus(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
bool enable = false;
int rc;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "BOOLEAN" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[1], out enable ) )
return TCL.TCL_ERROR;
rc = sqlite3_config( SQLITE_CONFIG_MEMSTATUS, enable );
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_config_lookaside SIZE COUNT
**
*/
static int test_config_lookaside(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc;
int sz = 0, cnt = 0;
Tcl_Obj pRet;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SIZE COUNT" );
return TCL.TCL_ERROR;
}
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out sz ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out cnt ) )
return TCL.TCL_ERROR;
pRet = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement(
interp, pRet, TCL.Tcl_NewIntObj( sqlite3GlobalConfig.szLookaside )
);
TCL.Tcl_ListObjAppendElement(
interp, pRet, TCL.Tcl_NewIntObj( sqlite3GlobalConfig.nLookaside )
);
rc = sqlite3_config( SQLITE_CONFIG_LOOKASIDE, sz, cnt );
TCL.Tcl_SetObjResult( interp, pRet );
return TCL.TCL_OK;
}
 
/*
** Usage: sqlite3_db_config_lookaside CONNECTION BUFID SIZE COUNT
**
** There are two static buffers with BUFID 1 and 2. Each static buffer
** is 10KB in size. A BUFID of 0 indicates that the buffer should be NULL
** which will cause sqlite3_db_config() to allocate space on its own.
*/
static int test_db_config_lookaside(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc;
int sz = 0, cnt = 0;
sqlite3 db = new sqlite3();
int bufid = 0;
byte[][] azBuf = new byte[2][];
//int getDbPointer(Tcl_Interp*, const char*, sqlite3*);
if ( objc != 5 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "BUFID SIZE COUNT" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[2], out bufid ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[3], out sz ) )
return TCL.TCL_ERROR;
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[4], out cnt ) )
return TCL.TCL_ERROR;
if ( bufid == 0 )
{
rc = sqlite3_db_config( db, SQLITE_DBCONFIG_LOOKASIDE, null, sz, cnt );
}
else if ( bufid >= 1 && bufid <= 2 && sz * cnt <= azBuf[0].Length )
{
rc = sqlite3_db_config( db, SQLITE_DBCONFIG_LOOKASIDE, azBuf[bufid], sz, cnt );
}
else
{
TCL.Tcl_AppendResult( interp, "illegal arguments - see documentation" );
return TCL.TCL_ERROR;
}
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( rc ) );
return TCL.TCL_OK;
}
 
/*
** Usage:
**
** sqlite3_config_heap NBYTE NMINALLOC
*/
//static int test_config_heap(
// object clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// static string zBuf; /* Use this memory */
// static int szBuf; /* Bytes allocated for zBuf */
// int nByte; /* Size of buffer to pass to sqlite3_config() */
// int nMinAlloc; /* Size of minimum allocation */
// int rc; /* Return code of sqlite3_config() */
 
// Tcl_Obj * CONST *aArg = objv[1];
// int nArg = objc-1;
 
// if( nArg!=2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "NBYTE NMINALLOC");
// return TCL.TCL_ERROR;
// }
// if( TCL.Tcl_GetIntFromObj(interp, aArg[0], out nByte) ) return TCL.TCL_ERROR;
// if( TCL.Tcl_GetIntFromObj(interp, aArg[1], out nMinAlloc) ) return TCL.TCL_ERROR;
 
// if( nByte==0 ){
// free( zBuf );
// zBuf = 0;
// szBuf = 0;
// rc = sqlite3_config(SQLITE_CONFIG_HEAP, (void)0, 0, 0);
// }else{
// zBuf = realloc(zBuf, nByte);
// szBuf = nByte;
// rc = sqlite3_config(SQLITE_CONFIG_HEAP, zBuf, nByte, nMinAlloc);
// }
 
// TCL.Tcl_SetResult(interp, (char )sqlite3TestErrorName(rc), TCL.Tcl_VOLATILE);
// return TCL.TCL_OK;
//}
 
/*
** tclcmd: sqlite3_config_error [DB]
**
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
** opcodes and verify that they return errors.
*/
//static int test_config_error(
// object clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// sqlite3 db;
// int getDbPointer(Tcl_Interp*, const char*, sqlite3*);
 
// if( objc!=2 && objc!=1 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "[DB]");
// return TCL.TCL_ERROR;
// }
// if( objc==2 ){
// if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) ) return TCL.TCL_ERROR;
// if( sqlite3_db_config(db, 99999)!=SQLITE_ERROR ){
// TCL.Tcl_AppendResult(interp,
// "sqlite3_db_config(db, 99999) does not return SQLITE_ERROR",
// (char)0);
// return TCL.TCL_ERROR;
// }
// }else{
// if( sqlite3_config(99999)!=SQLITE_ERROR ){
// TCL.Tcl_AppendResult(interp,
// "sqlite3_config(99999) does not return SQLITE_ERROR",
// (char)0);
// return TCL.TCL_ERROR;
// }
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage:
**
** sqlite3_dump_memsys3 FILENAME
** sqlite3_dump_memsys5 FILENAME
**
** Write a summary of unfreed memsys3 allocations to FILENAME.
*/
//static int test_dump_memsys3(
// object clientData,
// Tcl_Interp interp,
// int objc,
// Tcl_Obj[] objv
//){
// if( objc!=2 ){
// TCL.Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
// return TCL.TCL_ERROR;
// }
 
// switch( (int)clientData ){
// case 3: {
//#if SQLITE_ENABLE_MEMSYS3
// extern void sqlite3Memsys3Dump(const char);
// sqlite3Memsys3Dump(Tcl_GetString(objv[1]));
// break;
//#endif
// }
// case 5: {
//#if SQLITE_ENABLE_MEMSYS5
// extern void sqlite3Memsys5Dump(const char);
// sqlite3Memsys5Dump(Tcl_GetString(objv[1]));
// break;
//#endif
// }
// }
// return TCL.TCL_OK;
//}
 
/*
** Usage: sqlite3_status OPCODE RESETFLAG
**
** Return a list of three elements which are the sqlite3_status() return
** code, the current value, and the high-water mark value.
*/
class _aOp
{
public string zName;
public int op;
public _aOp( string zName, int op )
{
this.zName = zName;
this.op = op;
}
}
 
static int test_status(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc, iValue, mxValue;
int i, op = 0;
bool resetFlag = false;
string zOpName;
 
_aOp[] aOp = new _aOp[] {
new _aOp( "SQLITE_STATUS_MEMORY_USED", SQLITE_STATUS_MEMORY_USED ),
new _aOp( "SQLITE_STATUS_MALLOC_SIZE", SQLITE_STATUS_MALLOC_SIZE ),
new _aOp( "SQLITE_STATUS_PAGECACHE_USED", SQLITE_STATUS_PAGECACHE_USED ),
new _aOp( "SQLITE_STATUS_PAGECACHE_OVERFLOW", SQLITE_STATUS_PAGECACHE_OVERFLOW ),
new _aOp( "SQLITE_STATUS_PAGECACHE_SIZE", SQLITE_STATUS_PAGECACHE_SIZE ),
new _aOp( "SQLITE_STATUS_SCRATCH_USED", SQLITE_STATUS_SCRATCH_USED ),
new _aOp( "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW ),
new _aOp( "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE ),
new _aOp( "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK ),
new _aOp("SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT ),
};
Tcl_Obj pResult;
if ( objc != 3 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "PARAMETER RESETFLAG" );
return TCL.TCL_ERROR;
}
zOpName = TCL.Tcl_GetString( objv[1] );
for ( i = 0; i < ArraySize( aOp ); i++ )
{
if ( aOp[i].zName == zOpName )
{//strcmp(aOp[i].zName, zOpName)==0 ){
op = aOp[i].op;
break;
}
}
if ( i >= ArraySize( aOp ) )
{
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out op ) )
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[2], out resetFlag ) )
return TCL.TCL_ERROR;
iValue = 0;
mxValue = 0;
rc = sqlite3_status( op, ref iValue, ref mxValue, resetFlag ? 1 : 0 );
pResult = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( rc ) );
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( iValue ) );
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( mxValue ) );
TCL.Tcl_SetObjResult( interp, pResult );
return TCL.TCL_OK;
}
/*
** Usage: sqlite3_db_status DATABASE OPCODE RESETFLAG
**
** Return a list of three elements which are the sqlite3_db_status() return
** code, the current value, and the high-water mark value.
*/
static int test_db_status(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc, iValue, mxValue;
int i, op = 0;
bool resetFlag = false;
string zOpName;
sqlite3 db = null;
//int getDbPointer (Tcl_Interp*, const char*, sqlite3*);
//static const struct {
//string zName;
//int op;
//}
_aOp[] aOp = {
new _aOp( "LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED ),
new _aOp( "CACHE_USED", SQLITE_DBSTATUS_CACHE_USED ),
new _aOp( "SCHEMA_USED", SQLITE_DBSTATUS_SCHEMA_USED ),
new _aOp( "STMT_USED", SQLITE_DBSTATUS_STMT_USED ),
new _aOp( "LOOKASIDE_HIT", SQLITE_DBSTATUS_LOOKASIDE_HIT ),
new _aOp( "LOOKASIDE_MISS_SIZE", SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE ),
new _aOp( "LOOKASIDE_MISS_FULL", SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL )
};
Tcl_Obj pResult;
if ( objc != 4 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "PARAMETER RESETFLAG" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
zOpName = TCL.Tcl_GetString( objv[2] );
if ( zOpName.StartsWith( "SQLITE_" ) )
zOpName = zOpName.Remove( 0, 7 ); //zOpName += 7;
if ( zOpName.StartsWith( "DBSTATUS_" ) )
zOpName = zOpName.Remove( 0, 9 ); //zOpName += 9;
for ( i = 0; i < ArraySize( aOp ); i++ )
{
if ( aOp[i].zName == zOpName )
{
op = aOp[i].op;
break;
}
}
if ( i >= ArraySize( aOp ) )
{
if ( TCL.Tcl_GetIntFromObj( interp, objv[2], out op ) != 0 )
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[3], out resetFlag ) )
return TCL.TCL_ERROR;
iValue = 0;
mxValue = 0;
rc = sqlite3_db_status( db, op, ref iValue, ref mxValue, resetFlag ? 1 : 0 );
pResult = TCL.Tcl_NewObj();
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( rc ) );
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( iValue ) );
TCL.Tcl_ListObjAppendElement( null, pResult, TCL.Tcl_NewIntObj( mxValue ) );
TCL.Tcl_SetObjResult( interp, pResult );
return TCL.TCL_OK;
}
 
/*
** install_malloc_faultsim BOOLEAN
*/
static int test_install_malloc_faultsim(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc;
int isInstall;
bool bisInstall = false;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "BOOLEAN" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBooleanFromObj( interp, objv[1], out bisInstall ) )
{
return TCL.TCL_ERROR;
}
isInstall = bisInstall ? 1 : 0;
rc = faultsimInstall( isInstall );
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE );
return TCL.TCL_OK;
}
 
static int test_vfs_oom_test(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
//extern int sqlite3_memdebug_vfs_oom_test;
if ( objc > 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "?INTEGER?" );
return TCL.TCL_ERROR;
}
else if ( objc == 2 )
{
int iNew = 0;
if ( TCL.Tcl_GetIntFromObj( interp, objv[1], out iNew ) != 0 )
return TCL.TCL_ERROR;
sqlite3_memdebug_vfs_oom_test = iNew;
}
TCL.Tcl_SetObjResult( interp, TCL.Tcl_NewIntObj( sqlite3_memdebug_vfs_oom_test ) );
return TCL.TCL_OK;
}
 
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetest_malloc_Init( Tcl_Interp interp )
{
//static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
// int clientData;
//} aObjCmd[] = {
_aObjCmd[] aObjCmd = new _aObjCmd[] {
//{ "sqlite3_malloc", test_malloc ,0 },
//{ "sqlite3_realloc", test_realloc ,0 },
//{ "sqlite3_free", test_free ,0 },
//{ "memset", test_memset ,0 },
//{ "memget", test_memget ,0 },
//{ "sqlite3_memory_used", test_memory_used ,0 },
#if FALSE
new _aObjCmd( "sqlite3_memory_used", test_memory_used ,0 ),
new _aObjCmd( "sqlite3_memory_highwater", test_memory_highwater ,0),
#endif
//{ "sqlite3_memory_highwater", test_memory_highwater ,0 },
//{ "sqlite3_memdebug_backtrace", test_memdebug_backtrace ,0 },
new _aObjCmd( "sqlite3_memdebug_dump", test_memdebug_dump ,0 ),
new _aObjCmd( "sqlite3_memdebug_fail", test_memdebug_fail ,0 ),
//{ "sqlite3_memdebug_pending", test_memdebug_pending ,0 },
new _aObjCmd( "sqlite3_memdebug_settitle", test_memdebug_settitle ,0 ),
new _aObjCmd( "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count ,0),
//{ "sqlite3_memdebug_log", test_memdebug_log ,0 },
new _aObjCmd( "sqlite3_config_scratch", test_config_scratch ,0 ),
new _aObjCmd("sqlite3_config_pagecache", test_config_pagecache ,0 ),
//{ "sqlite3_config_alt_pcache", test_alt_pcache ,0 },
new _aObjCmd( "sqlite3_status", test_status,0 ),
new _aObjCmd( "sqlite3_db_status", test_db_status, 0 ),
new _aObjCmd( "install_malloc_faultsim", test_install_malloc_faultsim ,0),
//{ "sqlite3_config_heap", test_config_heap ,0 },
new _aObjCmd( "sqlite3_config_memstatus", test_config_memstatus ,0 ),
new _aObjCmd( "sqlite3_config_lookaside", test_config_lookaside ,0 ),
//{ "sqlite3_config_error", test_config_error ,0 },
new _aObjCmd( "sqlite3_config_uri",test_config_uri ,0 ),
new _aObjCmd( "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 ),
//{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
//{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
//{ "sqlite3_install_memsys3", test_install_memsys3 ,0 },
//{ "sqlite3_memdebug_vfs_oom_test", test_vfs_oom_test ,0 },
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )
{//<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
object c = (object)aObjCmd[i].clientData;
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, null );
}
return TCL.TCL_OK;
}
#endif
}
#endif
}
/trunk/testfixture/src/test_mutex_c.cs
@@ -0,0 +1,550 @@
using System.Diagnostics;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using System.Text;
 
 
public partial class Sqlite3
{
/*
** 2008 June 18
**
** 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 test logic for the sqlite3_mutex interfaces.
*************************************************************************
** 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: 2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7
**
*************************************************************************
*/
 
//#include "tcl.h"
//#include "sqlite3.h"
//#include "sqliteInt.h"
//#include <stdlib.h>
//#include <assert.h>
//#include <string.h>
 
/* defined in test1.c */
//string sqlite3TestErrorName(int);
 
/* A countable mutex */
public partial class sqlite3_mutex
{
public sqlite3_mutex pReal;
public int eType;
};
 
static Var.SQLITE3_GETSET disableInit = new Var.SQLITE3_GETSET( "disable_mutex_init" );
static Var.SQLITE3_GETSET disableTry = new Var.SQLITE3_GETSET( "disable_mutex_try" );
/* State variables */
public class test_mutex_globals
{
public bool isInstalled; /* True if installed */
public bool disableInit; /* True to cause sqlite3_initalize() to fail */
public bool disableTry; /* True to force sqlite3_mutex_try() to fail */
public bool isInit; /* True if initialized */
public sqlite3_mutex_methods m = new sqlite3_mutex_methods(); /* Interface to "real" mutex system */
public int[] aCounter = new int[8]; /* Number of grabs of each type of mutex */
public sqlite3_mutex[] aStatic = new sqlite3_mutex[6]; /* The six static mutexes */
 
public test_mutex_globals()
{
for ( int i = 0; i < aStatic.Length; i++ )
aStatic[i] = new sqlite3_mutex();
}
}
 
static test_mutex_globals g = new test_mutex_globals();
 
/* Return true if the countable mutex is currently held */
static bool counterMutexHeld( sqlite3_mutex p )
{
return g.m.xMutexHeld( p.pReal );
}
 
/* Return true if the countable mutex is not currently held */
static bool counterMutexNotheld( sqlite3_mutex p )
{
return g.m.xMutexNotheld( p.pReal );
}
 
/* Initialize the countable mutex interface
** Or, if g.disableInit is non-zero, then do not initialize but instead
** return the value of g.disableInit as the result code. This can be used
** to simulate an initialization failure.
*/
static int counterMutexInit()
{
int rc;
if ( g.disableInit )
return g.disableInit ? 1 : 0;
rc = g.m.xMutexInit();
g.isInit = true;
return rc;
}
 
/*
** Uninitialize the mutex subsystem
*/
static int counterMutexEnd()
{
g.isInit = false;
return g.m.xMutexEnd();
}
 
/*
** Allocate a countable mutex
*/
static sqlite3_mutex counterMutexAlloc( int eType )
{
sqlite3_mutex pReal;
sqlite3_mutex pRet = null;
 
Debug.Assert( g.isInit );
Debug.Assert( eType < 8 && eType >= 0 );
 
pReal = g.m.xMutexAlloc( eType );
if ( null == pReal )
return null;
 
if ( eType == SQLITE_MUTEX_FAST || eType == SQLITE_MUTEX_RECURSIVE )
{
pRet = new sqlite3_mutex();
;//(sqlite3_mutex)malloc( sizeof( sqlite3_mutex ) );
}
else
{
pRet = g.aStatic[eType - 2];
}
 
pRet.eType = eType;
pRet.pReal = pReal;
return pRet;
}
 
/*
** Free a countable mutex
*/
static void counterMutexFree( sqlite3_mutex p )
{
Debug.Assert( g.isInit );
g.m.xMutexFree( p.pReal );
if ( p.eType == SQLITE_MUTEX_FAST || p.eType == SQLITE_MUTEX_RECURSIVE )
{
p = null;//free(p);
}
}
 
/*
** Enter a countable mutex. Block until entry is safe.
*/
static void counterMutexEnter( sqlite3_mutex p )
{
Debug.Assert( g.isInit );
g.aCounter[p.eType]++;
g.m.xMutexEnter( p.pReal );
}
 
/*
** Try to enter a mutex. Return true on success.
*/
static int counterMutexTry( sqlite3_mutex p )
{
Debug.Assert( g.isInit );
g.aCounter[p.eType]++;
if ( g.disableTry )
return SQLITE_BUSY;
return g.m.xMutexTry( p.pReal );
}
 
/* Leave a mutex
*/
static void counterMutexLeave( sqlite3_mutex p )
{
Debug.Assert( g.isInit );
g.m.xMutexLeave( p.pReal );
}
 
/*
** sqlite3_shutdown
*/
static int test_shutdown(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc;
 
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
rc = sqlite3_shutdown();
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE );
return TCL.TCL_OK;
}
 
/*
** sqlite3_initialize
*/
static int test_initialize(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv )
{
int rc;
 
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
rc = sqlite3_initialize();
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE );
return TCL.TCL_OK;
}
 
/*
** install_mutex_counters BOOLEAN
*/
static int test_install_mutex_counters(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int rc = SQLITE_OK;
bool isInstall = false;
 
sqlite3_mutex_methods counter_methods = new sqlite3_mutex_methods(
(dxMutexInit)counterMutexInit,
(dxMutexEnd)counterMutexEnd,
(dxMutexAlloc)counterMutexAlloc,
(dxMutexFree)counterMutexFree,
(dxMutexEnter)counterMutexEnter,
(dxMutexTry)counterMutexTry,
(dxMutexLeave)counterMutexLeave,
(dxMutexHeld)counterMutexHeld,
(dxMutexNotheld)counterMutexNotheld
);
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "BOOLEAN" );
return TCL.TCL_ERROR;
}
if ( TCL.Tcl_GetBoolean( interp, objv[1], out isInstall ))
{
return TCL.TCL_ERROR;
}
 
Debug.Assert( isInstall == false || isInstall == true );
Debug.Assert( g.isInstalled == false || g.isInstalled == true );
if ( isInstall == g.isInstalled )
{
TCL.Tcl_AppendResult( interp, "mutex counters are " );
TCL.Tcl_AppendResult( interp, isInstall ? "already installed" : "not installed" );
return TCL.TCL_ERROR;
}
 
if ( isInstall )
{
Debug.Assert( g.m.xMutexAlloc == null );
rc = sqlite3_config( SQLITE_CONFIG_GETMUTEX, ref g.m );
if ( rc == SQLITE_OK )
{
sqlite3_config( SQLITE_CONFIG_MUTEX, counter_methods );
}
g.disableTry = false;
}
else
{
Debug.Assert( g.m.xMutexAlloc != null );
rc = sqlite3_config( SQLITE_CONFIG_MUTEX, g.m );
g.m = new sqlite3_mutex_methods();// memset( &g.m, 0, sizeof( sqlite3_mutex_methods ) );
}
 
if ( rc == SQLITE_OK )
{
g.isInstalled = isInstall;
}
 
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE );
return TCL.TCL_OK;
}
 
/*
** read_mutex_counters
*/
static int test_read_mutex_counters(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
Tcl_Obj pRet;
int ii;
string[] aName = new string[] {
"fast", "recursive", "static_master", "static_mem",
"static_open", "static_prng", "static_lru", "static_pmem"
};
 
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
pRet = TCL.Tcl_NewObj();
TCL.Tcl_IncrRefCount( pRet );
for ( ii = 0; ii < 8; ii++ )
{
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewStringObj( aName[ii], -1 ) );
TCL.Tcl_ListObjAppendElement( interp, pRet, TCL.Tcl_NewIntObj( g.aCounter[ii] ) );
}
TCL.Tcl_SetObjResult( interp, pRet );
TCL.Tcl_DecrRefCount( ref pRet );
 
return TCL.TCL_OK;
}
 
/*
** clear_mutex_counters
*/
static int test_clear_mutex_counters(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
int ii;
 
if ( objc != 1 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
for ( ii = 0; ii < 8; ii++ )
{
g.aCounter[ii] = 0;
}
return TCL.TCL_OK;
}
 
/*
** Create and free a mutex. Return the mutex pointer. The pointer
** will be invalid since the mutex has already been freed. The
** return pointer just checks to see if the mutex really was allocated.
*/
static int test_alloc_mutex(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv )
{
#if SQLITE_THREADSAFE
sqlite3_mutex p = sqlite3_mutex_alloc( SQLITE_MUTEX_FAST );
StringBuilder zBuf = new StringBuilder( 100 );
sqlite3_mutex_free( p );
sqlite3_snprintf( 100, zBuf, "->%p", p );
TCL.Tcl_AppendResult( interp, zBuf );
#endif
return TCL.TCL_OK;
}
 
/*
** sqlite3_config OPTION
**
** OPTION can be either one of the keywords:
**
** SQLITE_CONFIG_SINGLETHREAD
** SQLITE_CONFIG_MULTITHREAD
** SQLITE_CONFIG_SERIALIZED
**
** Or OPTION can be an raw integer.
*/
struct ConfigOption
{
public string zName;
public int iValue;
public ConfigOption( string zName, int iValue )
{
this.zName = zName;
this.iValue = iValue;
}
}
static bool Tcl_GetIndexFromObjStruct( Interp interp, TclObject to, ConfigOption[] table, int s, string msg, int flags, out int index )
{
try
{
for ( index = 0; index < table.Length; index++ )
{
if ( table[index].zName == msg )
return false;
}
return true;
}
catch
{
index = 0;
return true;
}
}
 
 
static int test_config(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
ConfigOption[] aOpt = new ConfigOption[] {
new ConfigOption("singlethread", SQLITE_CONFIG_SINGLETHREAD),
new ConfigOption("multithread", SQLITE_CONFIG_MULTITHREAD),
new ConfigOption("serialized", SQLITE_CONFIG_SERIALIZED),
new ConfigOption(null,0)
};
int s = aOpt.Length;//sizeof(struct ConfigOption);
int i = 0;
int rc;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "" );
return TCL.TCL_ERROR;
}
 
if ( Tcl_GetIndexFromObjStruct( interp, objv[1], aOpt, s, "flag", 0, out i ) )
{
if ( TCL.TCL_OK != TCL.Tcl_GetIntFromObj( interp, objv[1], out i ) )
{
return TCL.TCL_ERROR;
}
}
else
{
i = aOpt[i].iValue;
}
 
rc = sqlite3_config( i );
TCL.Tcl_SetResult( interp, sqlite3TestErrorName( rc ), TCL.TCL_VOLATILE );
return TCL.TCL_OK;
}
 
//static sqlite3 *getDbPointer(Tcl_Interp *pInterp, TCL.TCL_Obj *pObj){
//sqlite3 db;
//Tcl_CmdInfo info;
//string zCmd = TCL.Tcl_GetString(pObj);
//if( TCL.Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
// db = *((sqlite3 *)info.objClientData);
//}else{
// db = (sqlite3)sqlite3TestTextToPtr(zCmd);
//}
//Debug.Assert( db );
//return db;
 
static int test_enter_db_mutex(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db );
if ( null == db )
{
return TCL.TCL_ERROR;
}
sqlite3_mutex_enter( sqlite3_db_mutex( db ) );
return TCL.TCL_OK;
}
 
static int test_leave_db_mutex(
object clientdata,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
sqlite3 db = null;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db );
if ( null == db )
{
return TCL.TCL_ERROR;
}
sqlite3_mutex_leave( sqlite3_db_mutex( db ) );
return TCL.TCL_OK;
}
 
static public int Sqlitetest_mutex_Init( Tcl_Interp interp )
{
//static struct {
// string zName;
// Tcl_ObjCmdProc *xProc;
//}
_aObjCmd[] aCmd = new _aObjCmd[]{
new _aObjCmd( "sqlite3_shutdown", test_shutdown ),
new _aObjCmd( "sqlite3_initialize", test_initialize ),
new _aObjCmd( "sqlite3_config", test_config ),
 
new _aObjCmd("enter_db_mutex", test_enter_db_mutex ),
new _aObjCmd( "leave_db_mutex", test_leave_db_mutex ),
 
new _aObjCmd( "alloc_dealloc_mutex", test_alloc_mutex ),
new _aObjCmd( "install_mutex_counters", test_install_mutex_counters ),
new _aObjCmd( "read_mutex_counters", test_read_mutex_counters ),
new _aObjCmd( "clear_mutex_counters", test_clear_mutex_counters ),
};
int i;
for ( i = 0; i < aCmd.Length; i++ )
{//sizeof(aCmd)/sizeof(aCmd[0]); i++){
TCL.Tcl_CreateObjCommand( interp, aCmd[i].zName, aCmd[i].xProc, null, null );
}
 
TCL.Tcl_LinkVar(interp, "disable_mutex_init",disableInit, VarFlags.SQLITE3_LINK_INT );
//g.disableInit, VarFlags.SQLITE3_LINK_INT );
TCL.Tcl_LinkVar( interp, "disable_mutex_try",disableTry, VarFlags.SQLITE3_LINK_INT );
//g.disableTry, VarFlags.SQLITE3_LINK_INT );
return SQLITE_OK;
}
}
#endif
}
/trunk/testfixture/src/test_schema_c.cs
@@ -0,0 +1,435 @@
using System;
using System.Diagnostics;
using System.Text;
 
using i64 = System.Int64;
using u8 = System.Byte;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite_int64 = System.Int64;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
 
public partial class Sqlite3
{
/*
** 2006 June 10
**
** 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.
**
*************************************************************************
** Code for testing the virtual table interfaces. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
*************************************************************************
*/
 
/* The code in this file defines a sqlite3 virtual-table module that
** provides a read-only view of the current database schema. There is one
** row in the schema table for each column in the database schema.
*/
//#define SCHEMA \
//"CREATE TABLE x(" \
// "database," /* Name of database (i.e. main, temp etc.) */ \
// "tablename," /* Name of table */ \
// "cid," /* Column number (from left-to-right, 0 upward) */ \
// "name," /* Column name */ \
// "type," /* Specified type (i.e. VARCHAR(32)) */ \
// "not_null," /* Boolean. True if NOT NULL was specified */ \
// "dflt_value," /* Default value for this column */ \
// "pk" /* True if this column is part of the primary key */ \
//")"
const string SCHEMA = "CREATE TABLE x(" +
"database," +
"tablename," +
"cid," +
"name," +
"type," +
"not_null," +
"dflt_value," +
"pk" +
")";
 
/* If SQLITE_TEST is defined this code is preprocessed for use as part
** of the sqlite test binary "testfixture". Otherwise it is preprocessed
** to be compiled into an sqlite dynamic extension.
*/
//#if SQLITE_TEST
// #include "sqliteInt.h"
// #include "tcl.h"
//#else
// #include "sqlite3ext.h"
// SQLITE_EXTENSION_INIT1
//#endif
 
//#include <stdlib.h>
//#include <string.h>
//#include <Debug.Assert.h>
 
//typedef struct schema_vtab schema_vtab;
//typedef struct schema_cursor schema_cursor;
 
/* A schema table object */
class schema_vtab : sqlite3_vtab
{
// sqlite3_vtab base;
public sqlite3 db;
};
 
/* A schema table cursor object */
class schema_cursor : sqlite3_vtab_cursor
{
//sqlite3_vtab_cursor base;
public sqlite3_stmt pDbList;
public sqlite3_stmt pTableList;
public sqlite3_stmt pColumnList;
public int rowid;
};
 
/*
** None of this works unless we have virtual tables.
*/
#if !SQLITE_OMIT_VIRTUALTABLE
 
/*
** Table destructor for the schema module.
*/
static int schemaDestroy( ref object pVtab )
{
pVtab = null;//sqlite3_free(pVtab);
return 0;
}
 
/*
** Table constructor for the schema module.
*/
static int schemaCreate(
sqlite3 db,
object pAux,
int argc,
string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
)
{
int rc = SQLITE_NOMEM;
schema_vtab pVtab = new schema_vtab();//sqlite3_malloc(sizeof(schema_vtab));
if ( pVtab != null )
{
//memset(pVtab, 0, sizeof(schema_vtab));
pVtab.db = db;
#if !SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_declare_vtab( db, SCHEMA );
#endif
}
ppVtab = (sqlite3_vtab)pVtab;
pzErr = "";
return rc;
}
 
/*
** Open a new cursor on the schema table.
*/
static int schemaOpen( sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor )
{
int rc = SQLITE_NOMEM;
schema_cursor pCur;
pCur = new schema_cursor();//pCur = sqlite3_malloc(sizeof(schema_cursor));
//if ( pCur != null )
//{
//memset(pCur, 0, sizeof(schema_cursor));
ppCursor = (sqlite3_vtab_cursor)pCur;
rc = SQLITE_OK;
//}
return rc;
}
 
/*
** Close a schema table cursor.
*/
static int schemaClose( ref sqlite3_vtab_cursor cur )
{
schema_cursor pCur = (schema_cursor)cur;
sqlite3_finalize( pCur.pDbList );
sqlite3_finalize( pCur.pTableList );
sqlite3_finalize( pCur.pColumnList );
//sqlite3_free( pCur );
cur = null;//
return SQLITE_OK;
}
 
/*
** Retrieve a column of data.
*/
static int schemaColumn( sqlite3_vtab_cursor cur, sqlite3_context ctx, int i )
{
schema_cursor pCur = (schema_cursor)cur;
switch ( i )
{
case 0:
sqlite3_result_value( ctx, sqlite3_column_value( pCur.pDbList, 1 ) );
break;
case 1:
sqlite3_result_value( ctx, sqlite3_column_value( pCur.pTableList, 0 ) );
break;
default:
sqlite3_result_value( ctx, sqlite3_column_value( pCur.pColumnList, i - 2 ) );
break;
}
return SQLITE_OK;
}
 
/*
** Retrieve the current rowid.
*/
static int schemaRowid( sqlite3_vtab_cursor cur, out sqlite_int64 pRowid )
{
schema_cursor pCur = (schema_cursor)cur;
pRowid = pCur.rowid;
return SQLITE_OK;
}
 
static int finalize( ref sqlite3_stmt ppStmt )
{
int rc = sqlite3_finalize( ppStmt );
ppStmt = null;
return rc;
}
 
static int schemaEof( sqlite3_vtab_cursor cur )
{
schema_cursor pCur = (schema_cursor)cur;
return ( pCur.pDbList != null ? 0 : 1 );
}
 
/*
** Advance the cursor to the next row.
*/
static int schemaNext( sqlite3_vtab_cursor cur )
{
int rc = SQLITE_OK;
schema_cursor pCur = (schema_cursor)cur;
schema_vtab pVtab = (schema_vtab)( cur.pVtab );
string zSql = null;
 
while ( null == pCur.pColumnList || SQLITE_ROW != sqlite3_step( pCur.pColumnList ) )
{
if ( SQLITE_OK != ( rc = finalize( ref pCur.pColumnList ) ) )
goto next_exit;
 
while ( null == pCur.pTableList || SQLITE_ROW != sqlite3_step( pCur.pTableList ) )
{
if ( SQLITE_OK != ( rc = finalize( ref pCur.pTableList ) ) )
goto next_exit;
 
Debug.Assert( pCur.pDbList !=null);
while ( SQLITE_ROW != sqlite3_step( pCur.pDbList ) )
{
rc = finalize( ref pCur.pDbList );
goto next_exit;
}
 
/* Set zSql to the SQL to pull the list of tables from the
** sqlite_master (or sqlite_temp_master) table of the database
** identfied by the row pointed to by the SQL statement pCur.pDbList
** (iterating through a "PRAGMA database_list;" statement).
*/
if ( sqlite3_column_int( pCur.pDbList, 0 ) == 1 )
{
zSql = sqlite3_mprintf(
"SELECT name FROM sqlite_temp_master WHERE type='table'"
);
}
else
{
sqlite3_stmt pDbList = pCur.pDbList;
zSql = sqlite3_mprintf(
"SELECT name FROM %Q.sqlite_master WHERE type='table'",
sqlite3_column_text( pDbList, 1 )
);
}
//if( !zSql ){
// rc = SQLITE_NOMEM;
// goto next_exit;
//}
rc = sqlite3_prepare( pVtab.db, zSql, -1, ref pCur.pTableList, 0 );
//sqlite3_free(zSql);
if ( rc != SQLITE_OK )
goto next_exit;
}
 
/* Set zSql to the SQL to the table_info pragma for the table currently
** identified by the rows pointed to by statements pCur.pDbList and
** pCur.pTableList.
*/
zSql = sqlite3_mprintf( "PRAGMA %Q.table_info(%Q)",
sqlite3_column_text( pCur.pDbList, 1 ),
sqlite3_column_text( pCur.pTableList, 0 )
);
 
//if( !Sql ){
// rc = SQLITE_NOMEM;
// goto next_exit;
//}
rc = sqlite3_prepare( pVtab.db, zSql, -1, ref pCur.pColumnList, 0 );
//sqlite3_free(zSql);
if ( rc != SQLITE_OK )
goto next_exit;
}
pCur.rowid++;
 
next_exit:
/* TODO: Handle rc */
return rc;
}
 
/*
** Reset a schema table cursor.
*/
static int schemaFilter(
sqlite3_vtab_cursor pVtabCursor,
int idxNum,
string idxStr,
int argc,
sqlite3_value[] argv
)
{
int rc;
schema_vtab pVtab = (schema_vtab)( pVtabCursor.pVtab );
schema_cursor pCur = (schema_cursor)pVtabCursor;
pCur.rowid = 0;
finalize( ref pCur.pTableList );
finalize( ref pCur.pColumnList );
finalize( ref pCur.pDbList );
rc = sqlite3_prepare( pVtab.db, "PRAGMA database_list", -1, ref pCur.pDbList, 0 );
return ( rc == SQLITE_OK ? schemaNext( pVtabCursor ) : rc );
}
 
/*
** Analyse the WHERE condition.
*/
static int schemaBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
{
return SQLITE_OK;
}
 
/*
** A virtual table module that merely echos method calls into TCL
** variables.
*/
static sqlite3_module schemaModule = new sqlite3_module(
0, /* iVersion */
schemaCreate,
schemaCreate,
schemaBestIndex,
schemaDestroy,
schemaDestroy,
schemaOpen, /* xOpen - open a cursor */
schemaClose, /* xClose - close a cursor */
schemaFilter, /* xFilter - configure scan constraints */
schemaNext, /* xNext - advance a cursor */
schemaEof, /* xEof */
schemaColumn, /* xColumn - read data */
schemaRowid, /* xRowid - read data */
null, /* xUpdate */
null, /* xBegin */
null, /* xSync */
null, /* xCommit */
null, /* xRollback */
null, /* xFindMethod */
null /* xRename */
);
 
#endif //* !defined(SQLITE_OMIT_VIRTUALTABLE) */
 
#if SQLITE_TEST
 
/*
** Decode a pointer to an sqlite3 object.
*/
//extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
 
/*
** Register the schema virtual table module.
*/
static int register_schema_module(
ClientData clientData, /* Not used */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
#if !SQLITE_OMIT_VIRTUALTABLE
sqlite3_create_module( db, "schema", schemaModule, null );
#endif
return TCL.TCL_OK;
}
 
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetestschema_Init( Tcl_Interp interp )
{
//static struct {
// char *zName;
// Tcl_ObjCmdProc *xProc;
// void *clientData;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[]{
new _aObjCmd( "register_schema_module", register_schema_module, 0 ),
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++)
{
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, null );
}
return TCL.TCL_OK;
}
 
#else
 
/*
** Extension load function.
*/
int sqlite3_extension_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi);
#if !SQLITE_OMIT_VIRTUALTABLE
sqlite3_create_module(db, "schema", &schemaModule, 0);
#endif
return 0;
}
 
#endif
}
#endif
}
/trunk/testfixture/src/test_stat_c.cs
@@ -0,0 +1,716 @@
using System.Diagnostics;
 
using u8 = System.Byte;
using u32 = System.UInt32;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using DbPage = Sqlite3.PgHdr;
using sqlite_int64 = System.Int64;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_CmdInfo = tcl.lang.WrappedCommand;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
using System;
#endif
 
public partial class Sqlite3
{
/*
** 2010 July 12
**
** 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 an implementation of the "dbstat" virtual table.
**
** The dbstat virtual table is used to extract low-level formatting
** information from an SQLite database in order to implement the
** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
** for an example implementation.
*************************************************************************
** 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: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
**
**************************************************************************/
 
//#include "sqliteInt.h"
 
#if !SQLITE_OMIT_VIRTUALTABLE
 
/*
** Page paths:
**
** The value of the 'path' column describes the path taken from the
** root-node of the b-tree structure to each page. The value of the
** root-node path is '/'.
**
** The value of the path for the left-most child page of the root of
** a b-tree is '/000/'. (Btrees store content ordered from left to right
** so the pages to the left have smaller keys than the pages to the right.)
** The next to left-most child of the root page is
** '/001', and so on, each sibling page identified by a 3-digit hex
** value. The children of the 451st left-most sibling have paths such
** as '/1c2/000/, '/1c2/001/' etc.
**
** Overflow pages are specified by appending a '+' character and a
** six-digit hexadecimal value to the path to the cell they are linked
** from. For example, the three overflow pages in a chain linked from
** the left-most cell of the 450th child of the root page are identified
** by the paths:
**
** '/1c2/000+000000' // First page in overflow chain
** '/1c2/000+000001' // Second page in overflow chain
** '/1c2/000+000002' // Third page in overflow chain
**
** If the paths are sorted using the BINARY collation sequence, then
** the overflow pages associated with a cell will appear earlier in the
** sort-order than its child page:
**
** '/1c2/000/' // Left-most child of 451st child of root
*/
const string VTAB_SCHEMA =
"CREATE TABLE xx( " +
" name STRING, /* Name of table or index */" +
" path INTEGER, /* Path to page from root */" +
" pageno INTEGER, /* Page number */" +
" pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" +
" ncell INTEGER, /* Cells on page (0 for overflow) */" +
" payload INTEGER, /* Bytes of payload on this page */" +
" unused INTEGER, /* Bytes of unused space on this page */" +
" mx_payload INTEGER /* Largest payload size of all cells */" +
");";
 
#if FALSE
//#define VTAB_SCHEMA2 \
"CREATE TABLE yy( " \
" pageno INTEGER, /* B-tree page number */" \
" cellno INTEGER, /* Cell number within page */" \
" local INTEGER, /* Bytes of content stored locally */" \
" payload INTEGER, /* Total cell payload size */" \
" novfl INTEGER /* Number of overflow pages */" \
");"
#endif
 
 
//typedef struct StatTable StatTable;
//typedef struct StatCursor StatCursor;
//typedef struct StatPage StatPage;
//typedef struct StatCell StatCell;
 
class StatCell
{
public int nLocal; /* Bytes of local payload */
public u32 iChildPg; /* Child node (or 0 if this is a leaf) */
public int nOvfl; /* Entries in aOvfl[] */
public u32[] aOvfl; /* Array of overflow page numbers */
public int nLastOvfl; /* Bytes of payload on final overflow page */
public int iOvfl; /* Iterates through aOvfl[] */
};
 
class StatPage
{
public u32 iPgno;
public DbPage pPg;
public int iCell;
 
public string zPath; /* Path to this page */
 
/* Variables populated by statDecodePage(): */
public u8 flags; /* Copy of flags byte */
public int nCell; /* Number of cells on page */
public int nUnused; /* Number of unused bytes on page */
public StatCell[] aCell; /* Array of parsed cells */
public u32 iRightChildPg; /* Right-child page number (or 0) */
public int nMxPayload; /* Largest payload of any cell on this page */
};
 
class StatCursor : sqlite3_vtab_cursor
{
//sqlite3_vtab_cursor base;
public sqlite3_stmt pStmt; /* Iterates through set of root pages */
public int isEof; /* After pStmt has returned SQLITE_DONE */
 
public StatPage[] aPage = new StatPage[32];
public int iPage; /* Current entry in aPage[] */
 
/* Values to return. */
public string zName; /* Value of 'name' column */
public string zPath; /* Value of 'path' column */
public u32 iPageno; /* Value of 'pageno' column */
public string zPagetype; /* Value of 'pagetype' column */
public int nCell; /* Value of 'ncell' column */
public int nPayload; /* Value of 'payload' column */
public int nUnused; /* Value of 'unused' column */
public int nMxPayload; /* Value of 'mx_payload' column */
};
 
class StatTable : sqlite3_vtab
{
//sqlite3_vtab base;
public sqlite3 db;
};
 
//#if !get2byte
//# define get2byte(x) ((x)[0]<<8 | (x)[1])
//#endif
 
/*
** Connect to or create a statvfs virtual table.
*/
static int statConnect(
sqlite3 db,
object pAux,
int argc,
string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
)
{
StatTable pTab;
 
pTab = new StatTable();//(StatTable )sqlite3_malloc(sizeof(StatTable));
//memset(pTab, 0, sizeof(StatTable));
pTab.db = db;
 
sqlite3_declare_vtab( db, VTAB_SCHEMA );
ppVtab = pTab;
pzErr = "";
return SQLITE_OK;
}
 
/*
** Disconnect from or destroy a statvfs virtual table.
*/
static int statDisconnect( ref object pVtab )
{
pVtab = null;//sqlite3_free( pVtab );
return SQLITE_OK;
}
 
/*
** There is no "best-index". This virtual table always does a linear
** scan of the binary VFS log file.
*/
static int statBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
{
 
/* Records are always returned in ascending order of (name, path).
** If this will satisfy the client, set the orderByConsumed flag so that
** SQLite does not do an external sort.
*/
if ( ( pIdxInfo.nOrderBy == 1
&& pIdxInfo.aOrderBy[0].iColumn == 0
&& pIdxInfo.aOrderBy[0].desc == false
) ||
( pIdxInfo.nOrderBy == 2
&& pIdxInfo.aOrderBy[0].iColumn == 0
&& pIdxInfo.aOrderBy[0].desc == false
&& pIdxInfo.aOrderBy[1].iColumn == 1
&& pIdxInfo.aOrderBy[1].desc == false
)
)
{
pIdxInfo.orderByConsumed = true;
}
 
pIdxInfo.estimatedCost = 10.0;
return SQLITE_OK;
}
 
/*
** Open a new statvfs cursor.
*/
static int statOpen( sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor )
{
StatTable pTab = (StatTable)pVTab;
StatCursor pCsr;
int rc;
 
pCsr = new StatCursor();//(StatCursor )sqlite3_malloc(sizeof(StatCursor));
//memset(pCsr, 0, sizeof(StatCursor));
pCsr.pVtab = pVTab;
 
rc = sqlite3_prepare_v2( pTab.db,
"SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" +
" UNION ALL " +
"SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0" +
" ORDER BY name", -1,
ref pCsr.pStmt, 0
);
if ( rc != SQLITE_OK )
{
pCsr = null;//sqlite3_free( pCsr );
ppCursor = null;
return rc;
}
 
ppCursor = (sqlite3_vtab_cursor)pCsr;
return SQLITE_OK;
}
 
static void statClearPage( ref StatPage p )
{
int i;
if ( p != null && p.aCell != null )
{
for ( i = 0; i < p.nCell; i++ )
{
p.aCell[i].aOvfl = null;//sqlite3_free( p.aCell[i].aOvfl );
}
sqlite3PagerUnref( p.pPg );
// sqlite3_free( p.aCell );
// sqlite3_free( p.zPath );
}
p = new StatPage();//memset( p, 0, sizeof( StatPage ) );
}
 
static void statResetCsr( StatCursor pCsr )
{
int i;
sqlite3_reset( pCsr.pStmt );
for ( i = 0; i < ArraySize( pCsr.aPage ); i++ )
{
statClearPage( ref pCsr.aPage[i] );
}
pCsr.iPage = 0;
//sqlite3_free(pCsr.zPath);
pCsr.zPath = null;
}
 
/*
** Close a statvfs cursor.
*/
static int statClose( ref sqlite3_vtab_cursor pCursor )
{
StatCursor pCsr = (StatCursor)pCursor;
statResetCsr( pCsr );
sqlite3_finalize( pCsr.pStmt );
pCsr = null;//sqlite3_free( pCsr );
return SQLITE_OK;
}
 
static void getLocalPayload(
int nUsable, /* Usable bytes per page */
u8 flags, /* Page flags */
int nTotal, /* Total record (payload) size */
out int pnLocal /* OUT: Bytes stored locally */
)
{
int nLocal;
int nMinLocal;
int nMaxLocal;
 
if ( flags == 0x0D )
{ /* Table leaf node */
nMinLocal = ( nUsable - 12 ) * 32 / 255 - 23;
nMaxLocal = nUsable - 35;
}
else
{ /* Index interior and leaf nodes */
nMinLocal = ( nUsable - 12 ) * 32 / 255 - 23;
nMaxLocal = ( nUsable - 12 ) * 64 / 255 - 23;
}
 
nLocal = nMinLocal + ( nTotal - nMinLocal ) % ( nUsable - 4 );
if ( nLocal > nMaxLocal )
nLocal = nMinLocal;
pnLocal = nLocal;
}
 
static int statDecodePage( Btree pBt, StatPage p )
{
int nUnused;
int iOff;
int nHdr;
int isLeaf;
 
u8[] aData = sqlite3PagerGetData( p.pPg );
u8[] aHdr = new byte[p.iPgno == 1 ? aData.Length - 100 : aData.Length];
Buffer.BlockCopy( aData, p.iPgno == 1 ? 100 : 0, aHdr, 0, aHdr.Length );
 
p.flags = aHdr[0];
p.nCell = get2byte( aHdr, 3 );
p.nMxPayload = 0;
 
isLeaf = ( p.flags == 0x0A || p.flags == 0x0D ) ? 1 : 0;
nHdr = 12 - isLeaf * 4 + ( ( p.iPgno == 1 ) ? 1 : 0 ) * 100;
 
nUnused = get2byte( aHdr, 5 ) - nHdr - 2 * p.nCell;
nUnused += (int)aHdr[7];
iOff = get2byte( aHdr, 1 );
while ( iOff != 0 )
{
nUnused += get2byte( aData, iOff + 2 );
iOff = get2byte( aData, iOff );
}
p.nUnused = nUnused;
p.iRightChildPg = isLeaf != 0 ? 0 : sqlite3Get4byte( aHdr, 8 );
 
if ( p.nCell != 0 )
{
int i; /* Used to iterate through cells */
int nUsable = sqlite3BtreeGetPageSize( pBt ) - sqlite3BtreeGetReserve( pBt );
 
p.aCell = new StatCell[p.nCell + 1];// sqlite3_malloc( ( p.nCell + 1 ) * sizeof( StatCell ) );
//memset(p.aCell, 0, (p.nCell+1) * sizeof(StatCell));
 
for ( i = 0; i < p.nCell; i++ )
{
p.aCell[i] = new StatCell();
StatCell pCell = p.aCell[i];
 
iOff = get2byte( aData, nHdr + i * 2 );
if ( 0 == isLeaf )
{
pCell.iChildPg = sqlite3Get4byte( aData, iOff );
iOff += 4;
}
if ( p.flags == 0x05 )
{
/* A table interior node. nPayload==0. */
}
else
{
u32 nPayload; /* Bytes of payload total (local+overflow) */
int nLocal; /* Bytes of payload stored locally */
iOff += getVarint32( aData, iOff, out nPayload );
if ( p.flags == 0x0D )
{
ulong dummy;
iOff += sqlite3GetVarint( aData, iOff, out dummy );
}
if ( nPayload > p.nMxPayload )
p.nMxPayload = (int)nPayload;
getLocalPayload( nUsable, p.flags, (int)nPayload, out nLocal );
pCell.nLocal = nLocal;
Debug.Assert( nPayload >= nLocal );
Debug.Assert( nLocal <= ( nUsable - 35 ) );
if ( nPayload > nLocal )
{
int j;
int nOvfl = (int)( ( nPayload - nLocal ) + nUsable - 4 - 1 ) / ( nUsable - 4 );
pCell.nLastOvfl = (int)( nPayload - nLocal ) - ( nOvfl - 1 ) * ( nUsable - 4 );
pCell.nOvfl = nOvfl;
pCell.aOvfl = new uint[nOvfl];//sqlite3_malloc(sizeof(u32)*nOvfl);
pCell.aOvfl[0] = sqlite3Get4byte( aData, iOff + nLocal );
for ( j = 1; j < nOvfl; j++ )
{
int rc;
u32 iPrev = pCell.aOvfl[j - 1];
DbPage pPg = null;
rc = sqlite3PagerGet( sqlite3BtreePager( pBt ), iPrev, ref pPg );
if ( rc != SQLITE_OK )
{
Debug.Assert( pPg == null );
return rc;
}
pCell.aOvfl[j] = sqlite3Get4byte( sqlite3PagerGetData( pPg ) );
sqlite3PagerUnref( pPg );
}
}
}
}
}
 
return SQLITE_OK;
}
 
/*
** Move a statvfs cursor to the next entry in the file.
*/
static int statNext( sqlite3_vtab_cursor pCursor )
{
int rc = 0;
int nPayload;
StatCursor pCsr = (StatCursor)pCursor;
StatTable pTab = (StatTable)pCursor.pVtab;
Btree pBt = pTab.db.aDb[0].pBt;
Pager pPager = sqlite3BtreePager( pBt );
 
//sqlite3_free(pCsr.zPath);
pCsr.zPath = null;
 
if ( pCsr.aPage[0].pPg == null )
{
rc = sqlite3_step( pCsr.pStmt );
if ( rc == SQLITE_ROW )
{
u32 nPage;
u32 iRoot = (u32)sqlite3_column_int64( pCsr.pStmt, 1 );
sqlite3PagerPagecount( pPager, out nPage );
if ( nPage == 0 )
{
pCsr.isEof = 1;
return sqlite3_reset( pCsr.pStmt );
}
rc = sqlite3PagerGet( pPager, iRoot, ref pCsr.aPage[0].pPg );
pCsr.aPage[0].iPgno = iRoot;
pCsr.aPage[0].iCell = 0;
pCsr.aPage[0].zPath = sqlite3_mprintf( "/" );
pCsr.iPage = 0;
}
else
{
pCsr.isEof = 1;
return sqlite3_reset( pCsr.pStmt );
}
}
else
{
 
/* Page p itself has already been visited. */
StatPage p = pCsr.aPage[pCsr.iPage];
StatPage p1 = pCsr.aPage[pCsr.iPage + 1];
 
while ( p.iCell < p.nCell )
{
StatCell pCell = p.aCell[p.iCell];
if ( pCell.iOvfl < pCell.nOvfl )
{
int nUsable = sqlite3BtreeGetPageSize( pBt ) - sqlite3BtreeGetReserve( pBt );
pCsr.zName = sqlite3_column_text( pCsr.pStmt, 0 );
pCsr.iPageno = pCell.aOvfl[pCell.iOvfl];
pCsr.zPagetype = "overflow";
pCsr.nCell = 0;
pCsr.nMxPayload = 0;
pCsr.zPath = sqlite3_mprintf(
"%s%.3x+%.6x", p.zPath, p.iCell, pCell.iOvfl
);
if ( pCell.iOvfl < pCell.nOvfl - 1 )
{
pCsr.nUnused = 0;
pCsr.nPayload = nUsable - 4;
}
else
{
pCsr.nPayload = pCell.nLastOvfl;
pCsr.nUnused = nUsable - 4 - pCsr.nPayload;
}
pCell.iOvfl++;
return SQLITE_OK;
}
if ( p.iRightChildPg != 0 )
break;
p.iCell++;
}
 
while ( 0 == p.iRightChildPg || p.iCell > p.nCell )
{
statClearPage( ref p );
pCsr.aPage[pCsr.iPage] = p;
if ( pCsr.iPage == 0 )
return statNext( pCursor );
pCsr.iPage--;
p = pCsr.aPage[pCsr.iPage];
if ( pCsr.aPage[pCsr.iPage + 1] == null )
pCsr.aPage[pCsr.iPage + 1] = new StatPage();
p1 = pCsr.aPage[pCsr.iPage + 1];
}
pCsr.iPage++;
Debug.Assert( p == pCsr.aPage[pCsr.iPage - 1] );
 
if ( p.iCell == p.nCell )
{
p1.iPgno = p.iRightChildPg;
}
else
{
p1.iPgno = p.aCell[p.iCell].iChildPg;
}
rc = sqlite3PagerGet( pPager, p1.iPgno, ref p1.pPg );
p1.iCell = 0;
p1.zPath = sqlite3_mprintf( "%s%.3x/", p.zPath, p.iCell );
p.iCell++;
}
 
 
/* Populate the StatCursor fields with the values to be returned
** by the xColumn() and xRowid() methods.
*/
if ( rc == SQLITE_OK )
{
int i;
StatPage p = pCsr.aPage[pCsr.iPage];
pCsr.zName = sqlite3_column_text( pCsr.pStmt, 0 );
pCsr.iPageno = p.iPgno;
 
statDecodePage( pBt, p );
 
switch ( p.flags )
{
case 0x05: /* table internal */
case 0x02: /* index internal */
pCsr.zPagetype = "internal";
break;
case 0x0D: /* table leaf */
case 0x0A: /* index leaf */
pCsr.zPagetype = "leaf";
break;
default:
pCsr.zPagetype = "corrupted";
break;
}
pCsr.nCell = p.nCell;
pCsr.nUnused = p.nUnused;
pCsr.nMxPayload = p.nMxPayload;
pCsr.zPath = sqlite3_mprintf( "%s", p.zPath );
nPayload = 0;
for ( i = 0; i < p.nCell; i++ )
{
nPayload += p.aCell[i].nLocal;
}
pCsr.nPayload = nPayload;
}
 
return rc;
}
 
static int statEof( sqlite3_vtab_cursor pCursor )
{
StatCursor pCsr = (StatCursor)pCursor;
return pCsr.isEof;
}
 
static int statFilter(
sqlite3_vtab_cursor pCursor,
int idxNum, string idxStr,
int argc, sqlite3_value[] argv
)
{
StatCursor pCsr = (StatCursor)pCursor;
 
statResetCsr( pCsr );
return statNext( pCursor );
}
 
static int statColumn(
sqlite3_vtab_cursor pCursor,
sqlite3_context ctx,
int i
)
{
StatCursor pCsr = (StatCursor)pCursor;
switch ( i )
{
case 0: /* name */
sqlite3_result_text( ctx, pCsr.zName, -1, SQLITE_STATIC );
break;
case 1: /* path */
sqlite3_result_text( ctx, pCsr.zPath, -1, SQLITE_TRANSIENT );
break;
case 2: /* pageno */
sqlite3_result_int64( ctx, pCsr.iPageno );
break;
case 3: /* pagetype */
sqlite3_result_text( ctx, pCsr.zPagetype, -1, SQLITE_STATIC );
break;
case 4: /* ncell */
sqlite3_result_int( ctx, pCsr.nCell );
break;
case 5: /* payload */
sqlite3_result_int( ctx, pCsr.nPayload );
break;
case 6: /* unused */
sqlite3_result_int( ctx, pCsr.nUnused );
break;
case 7: /* mx_payload */
sqlite3_result_int( ctx, pCsr.nMxPayload );
break;
}
return SQLITE_OK;
}
 
static int statRowid( sqlite3_vtab_cursor pCursor, out sqlite_int64 pRowid )
{
StatCursor pCsr = (StatCursor)pCursor;
pRowid = pCsr.iPageno;
return SQLITE_OK;
}
 
static sqlite3_module dbstat_module = new sqlite3_module(
0, /* iVersion */
statConnect, /* xCreate */
statConnect, /* xConnect */
statBestIndex, /* xBestIndex */
statDisconnect, /* xDisconnect */
statDisconnect, /* xDestroy */
statOpen, /* xOpen - open a cursor */
statClose, /* xClose - close a cursor */
statFilter, /* xFilter - configure scan constraints */
statNext, /* xNext - advance a cursor */
statEof, /* xEof - check for end of scan */
statColumn, /* xColumn - read data */
statRowid, /* xRowid - read data */
null, /* xUpdate */
null, /* xBegin */
null, /* xSync */
null, /* xCommit */
null, /* xRollback */
null, /* xFindMethod */
null /* xRename */
);
 
static int sqlite3_dbstat_register( sqlite3 db )
{
sqlite3_create_module( db, "dbstat", dbstat_module, 0 );
return SQLITE_OK;
}
 
#endif
 
#if SQLITE_TEST
//#include <tcl.h>
 
static int test_dbstat(
object clientData,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
#if SQLITE_OMIT_VIRTUALTABLE
Tcl_AppendResult(interp, "dbstat not available because of "
"SQLITE_OMIT_VIRTUALTABLE", (void*)0);
return TCL.TCL_ERROR;
#else
//sqlite3 db;
string zDb;
Tcl_CmdInfo cmdInfo;
 
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
 
zDb = TCL.Tcl_GetString( objv[1] );
if ( !TCL.Tcl_GetCommandInfo( interp, zDb, out cmdInfo ) )
{
sqlite3 db = ( (SqliteDb)cmdInfo.objClientData ).db;
sqlite3_dbstat_register( db );
}
return TCL.TCL_OK;
#endif
}
 
public static int SqlitetestStat_Init( Tcl_Interp interp )
{
TCL.Tcl_CreateObjCommand( interp, "register_dbstat_vtab", test_dbstat, null, null );
return TCL.TCL_OK;
}
#endif
}
}
/trunk/testfixture/src/test_tclvar_c.cs
@@ -0,0 +1,364 @@
using System;
using System.Diagnostics;
 
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite_int64 = System.Int64;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
 
public partial class Sqlite3
{
/*
** 2006 June 13
**
** 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.
**
*************************************************************************
** Code for testing the virtual table interfaces. This code
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** The emphasis of this file is a virtual table that provides
** access to TCL variables.
*/
//#include "sqliteInt.h"
//#include "tcl.h"
//#include <stdlib.h>
//#include <string.h>
 
#if !SQLITE_OMIT_VIRTUALTABLE
 
//typedef struct tclvar_vtab tclvar_vtab;
//typedef struct tclvar_cursor tclvar_cursor;
 
/*
** A tclvar virtual-table object
*/
class tclvar_vtab : sqlite3_vtab {
//sqlite3_vtab base;
public Tcl_Interp interp;
};
 
/* A tclvar cursor object */
class tclvar_cursor : sqlite3_vtab_cursor {
//sqlite3_vtab_cursor base;
 
public Tcl_Obj pList1; /* Result of [info vars ?pattern?] */
public Tcl_Obj pList2; /* Result of [array names [lindex $pList1 $i1]] */
public int i1; /* Current item in pList1 */
public int i2; /* Current item (if any) in pList2 */
};
 
/* Methods for the tclvar module */
static int tclvarConnect(
sqlite3 db,
object pAux,
int argc,
string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
){
tclvar_vtab pVtab;
string zSchema =
"CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
pVtab = new tclvar_vtab();//sqlite3MallocZero( sizeof(*pVtab) );
//if( pVtab==0 ) return SQLITE_NOMEM;
ppVtab = pVtab;//*ppVtab = pVtab.base;
pVtab.interp = (Tcl_Interp)pAux;
sqlite3_declare_vtab(db, zSchema);
pzErr = "";
return SQLITE_OK;
}
/* Note that for this virtual table, the xCreate and xConnect
** methods are identical. */
 
static int tclvarDisconnect(ref object pVtab){
//sqlite3_free(pVtab);
pVtab = null;
return SQLITE_OK;
}
/* The xDisconnect and xDestroy methods are also the same */
 
/*
** Open a new tclvar cursor.
*/
static int tclvarOpen( sqlite3_vtab pVTab, out sqlite3_vtab_cursor ppCursor )
{
//tclvar_cursor pCur;
//pCur = sqlite3MallocZero(sizeof(tclvar_cursor));
//*ppCursor = pCur.base;
ppCursor = new tclvar_cursor();
return SQLITE_OK;
}
 
/*
** Close a tclvar cursor.
*/
static int tclvarClose( ref sqlite3_vtab_cursor cur )
{
tclvar_cursor pCur = (tclvar_cursor )cur;
if( pCur.pList1 != null){
TCL.Tcl_DecrRefCount(ref pCur.pList1);
}
if( pCur.pList2 != null){
TCL.Tcl_DecrRefCount( ref pCur.pList2 );
}
cur = null;//sqlite3_free(pCur);
return SQLITE_OK;
}
 
/*
** Returns 1 if data is ready, or 0 if not.
*/
static int next2(Tcl_Interp interp, tclvar_cursor pCur, Tcl_Obj pObj){
Tcl_Obj p;
 
if( pObj != null){
if( null==pCur.pList2 ){
p = TCL.Tcl_NewStringObj("array names", -1);
TCL.Tcl_IncrRefCount(p);
TCL.Tcl_ListObjAppendElement(null, p, pObj);
TCL.Tcl_EvalObjEx(interp, p, TCL.TCL_EVAL_GLOBAL);
TCL.Tcl_DecrRefCount(ref p);
pCur.pList2 = TCL.Tcl_GetObjResult(interp);
TCL.Tcl_IncrRefCount(pCur.pList2);
Debug.Assert( pCur.i2 == 0 );
}
else
{
int n = 0;
pCur.i2++;
TCL.Tcl_ListObjLength(null, pCur.pList2, out n);
if( pCur.i2>=n ){
TCL.Tcl_DecrRefCount(ref pCur.pList2);
pCur.pList2 = null;
pCur.i2 = 0;
return 0;
}
}
}
 
return 1;
}
 
static int tclvarNext(sqlite3_vtab_cursor cur){
Tcl_Obj pObj = null;
int n = 0;
int ok = 0;
 
tclvar_cursor pCur = (tclvar_cursor )cur;
Tcl_Interp interp = ((tclvar_vtab )(cur.pVtab)).interp;
 
TCL.Tcl_ListObjLength( null, pCur.pList1, out n );
while( 0==ok && pCur.i1<n ){
TCL.Tcl_ListObjIndex( null, pCur.pList1, pCur.i1, out pObj );
ok = next2(interp, pCur, pObj);
if( 0==ok ){
pCur.i1++;
}
}
 
return 0;
}
 
static int tclvarFilter(
sqlite3_vtab_cursor pVtabCursor,
int idxNum, string idxStr,
int argc, sqlite3_value[] argv
){
tclvar_cursor pCur = (tclvar_cursor )pVtabCursor;
Tcl_Interp interp = ((tclvar_vtab )(pVtabCursor.pVtab)).interp;
 
Tcl_Obj p = TCL.Tcl_NewStringObj("info vars", -1);
TCL.Tcl_IncrRefCount(p);
 
Debug.Assert( argc==0 || argc==1 );
if( argc==1 ){
Tcl_Obj pArg = TCL.Tcl_NewStringObj((string)sqlite3_value_text(argv[0]), -1);
TCL.Tcl_ListObjAppendElement(null, p, pArg);
}
TCL.Tcl_EvalObjEx(interp, p, TCL.TCL_EVAL_GLOBAL);
if( pCur.pList1 !=null){
TCL.Tcl_DecrRefCount(ref pCur.pList1);
}
if( pCur.pList2 !=null ){
TCL.Tcl_DecrRefCount(ref pCur.pList2);
pCur.pList2 = null;
}
pCur.i1 = 0;
pCur.i2 = 0;
pCur.pList1 = TCL.Tcl_GetObjResult(interp);
TCL.Tcl_IncrRefCount(pCur.pList1);
Debug.Assert( pCur.i1==0 && pCur.i2==0 && pCur.pList2==null );
 
TCL.Tcl_DecrRefCount(ref p);
return tclvarNext(pVtabCursor);
}
 
static int tclvarColumn(sqlite3_vtab_cursor cur, sqlite3_context ctx, int i){
Tcl_Obj p1=null;
Tcl_Obj p2=null;
string z1;
string z2 = "";
tclvar_cursor pCur = (tclvar_cursor)cur;
Tcl_Interp interp = ((tclvar_vtab )cur.pVtab).interp;
 
TCL.Tcl_ListObjIndex( interp, pCur.pList1, pCur.i1, out p1 );
TCL.Tcl_ListObjIndex( interp, pCur.pList2, pCur.i2, out p2 );
z1 = TCL.Tcl_GetString(p1);
if( p2!=null ){
z2 = TCL.Tcl_GetString(p2);
}
switch (i) {
case 0: {
sqlite3_result_text(ctx, z1, -1, SQLITE_TRANSIENT);
break;
}
case 1: {
sqlite3_result_text(ctx, z2, -1, SQLITE_TRANSIENT);
break;
}
case 2: {
Tcl_Obj pVal = TCL.Tcl_GetVar2Ex( interp, z1, z2 == "" ? null : z2, (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY );
sqlite3_result_text( ctx, TCL.Tcl_GetString( pVal ), -1, SQLITE_TRANSIENT );
break;
}
}
return SQLITE_OK;
}
 
static int tclvarRowid( sqlite3_vtab_cursor cur, out sqlite_int64 pRowid )
{
pRowid = 0;
return SQLITE_OK;
}
 
static int tclvarEof(sqlite3_vtab_cursor cur){
tclvar_cursor pCur = (tclvar_cursor)cur;
return ( pCur.pList2 != null ? 0 : 1 );
}
 
static int tclvarBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
{
int ii;
 
for(ii=0; ii<pIdxInfo.nConstraint; ii++){
sqlite3_index_constraint pCons = pIdxInfo.aConstraint[ii];
if( pCons.iColumn==0 && pCons.usable
&& pCons.op==SQLITE_INDEX_CONSTRAINT_EQ ){
sqlite3_index_constraint_usage pUsage = new sqlite3_index_constraint_usage();
pUsage = pIdxInfo.aConstraintUsage[ii];
pUsage.omit = false;
pUsage.argvIndex = 1;
return SQLITE_OK;
}
}
 
for(ii=0; ii<pIdxInfo.nConstraint; ii++){
sqlite3_index_constraint pCons = pIdxInfo.aConstraint[ii];
if( pCons.iColumn==0 && pCons.usable
&& pCons.op==SQLITE_INDEX_CONSTRAINT_MATCH ){
sqlite3_index_constraint_usage pUsage = new sqlite3_index_constraint_usage();
pUsage = pIdxInfo.aConstraintUsage[ii];
pUsage.omit = true;
pUsage.argvIndex = 1;
return SQLITE_OK;
}
}
 
return SQLITE_OK;
}
 
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
*/
static sqlite3_module tclvarModule = new sqlite3_module(
0, /* iVersion */
tclvarConnect,
tclvarConnect,
tclvarBestIndex,
tclvarDisconnect,
tclvarDisconnect,
tclvarOpen, /* xOpen - open a cursor */
tclvarClose, /* xClose - close a cursor */
tclvarFilter, /* xFilter - configure scan constraints */
tclvarNext, /* xNext - advance a cursor */
tclvarEof, /* xEof - check for end of scan */
tclvarColumn, /* xColumn - read data */
tclvarRowid, /* xRowid - read data */
null, /* xUpdate */
null, /* xBegin */
null, /* xSync */
null, /* xCommit */
null, /* xRollback */
null, /* xFindMethod */
null /* xRename */
);
 
/*
** Decode a pointer to an sqlite3 object.
*/
//extern int getDbPointer(Tcl_Interp *interp, string zA, sqlite3 **ppDb);
 
/*
** Register the echo virtual table module.
*/
static int register_tclvar_module(
ClientData clientData,/* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
){
sqlite3 db=null;
if( objc!=2 ){
TCL.Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL.TCL_ERROR;
}
if( getDbPointer(interp, TCL.Tcl_GetString(objv[1]), out db) !=0) return TCL.TCL_ERROR;
#if !SQLITE_OMIT_VIRTUALTABLE
sqlite3_create_module(db, "tclvar", tclvarModule, interp);
#endif
return TCL.TCL_OK;
}
 
#endif
 
 
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetesttclvar_Init(Tcl_Interp interp){
#if !SQLITE_OMIT_VIRTUALTABLE
//static struct {
// char *zName;
// Tcl_ObjCmdProc *xProc;
// void clientData;
//}
_aObjCmd[] aObjCmd = new _aObjCmd[] {
new _aObjCmd( "register_tclvar_module", register_tclvar_module, 0 ),
};
int i;
for(i=0; i<aObjCmd.Length;i++)//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++)
{
TCL.Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, null);
}
#endif
return TCL.TCL_OK;
}
}
#endif
}
/trunk/testfixture/src/test_vfs_c.cs
@@ -0,0 +1,1523 @@
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
}
/trunk/testfixture/src/test_vfstrace_c.cs
@@ -0,0 +1,927 @@
using System.Diagnostics;
 
using sqlite_int64 = System.Int64;
using sqlite3_int64 = System.Int64;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite3_stmt = Community.CsharpSqlite.Sqlite3.Vdbe;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using System.Text;
using System;
 
public partial class Sqlite3
{
/*
** 2011 March 16
**
** 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 implements a VFS shim that writes diagnostic
** output for each VFS call, similar to "strace".
**
** USAGE:
**
** This source file exports a single symbol which is the name of a
** function:
**
** int vfstrace_register(
** string zTraceName, // Name of the newly constructed VFS
** string zOldVfsName, // Name of the underlying VFS
** int (*xOut)(const char*,void), // Output routine. ex: fputs
** void pOutArg, // 2nd argument to xOut. ex: stderr
** int makeDefault // Make the new VFS the default
** );
**
** Applications that want to trace their VFS usage must provide a callback
** function with this prototype:
**
** int traceOutput(string zMessage, object pAppData);
**
** This function will "output" the trace messages, where "output" can
** mean different things to different applications. The traceOutput function
** for the command-line shell (see shell.c) is "fputs" from the standard
** library, which means that all trace output is written on the stream
** specified by the second argument. In the case of the command-line shell
** the second argument is stderr. Other applications might choose to output
** trace information to a file, over a socket, or write it into a buffer.
**
** The vfstrace_register() function creates a new "shim" VFS named by
** the zTraceName parameter. A "shim" VFS is an SQLite backend that does
** not really perform the duties of a true backend, but simply filters or
** interprets VFS calls before passing them off to another VFS which does
** the actual work. In this case the other VFS - the one that does the
** real work - is identified by the second parameter, zOldVfsName. If
** the the 2nd parameter is NULL then the default VFS is used. The common
** case is for the 2nd parameter to be NULL.
**
** The third and fourth parameters are the pointer to the output function
** and the second argument to the output function. For the SQLite
** command-line shell, when the -vfstrace option is used, these parameters
** are fputs and stderr, respectively.
**
** The fifth argument is true (non-zero) to cause the newly created VFS
** to become the default VFS. The common case is for the fifth parameter
** to be true.
**
** The call to vfstrace_register() simply creates the shim VFS that does
** tracing. The application must also arrange to use the new VFS for
** all database connections that are created and for which tracing is
** desired. This can be done by specifying the trace VFS using URI filename
** notation, or by specifying the trace VFS as the 4th parameter to
** sqlite3_open_v2() or by making the trace VFS be the default (by setting
** the 5th parameter of vfstrace_register() to 1).
**
**
** ENABLING VFSTRACE IN A COMMAND-LINE SHELL
**
** The SQLite command line shell implemented by the shell.c source file
** can be used with this module. To compile in -vfstrace support, first
** gather this file (test_vfstrace.c), the shell source file (shell.c),
** and the SQLite amalgamation source files (sqlite3.c, sqlite3.h) into
** the working directory. Then compile using a command like the following:
**
** gcc -o sqlite3 -Os -I. -DSQLITE_ENABLE_VFSTRACE \
** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE \
** -DHAVE_READLINE -DHAVE_USLEEP=1 \
** shell.c test_vfstrace.c sqlite3.c -ldl -lreadline -lncurses
**
** The gcc command above works on Linux and provides (in addition to the
** -vfstrace option) support for FTS3 and FTS4, RTREE, and command-line
** editing using the readline library. The command-line shell does not
** use threads so we added -DSQLITE_THREADSAFE=0 just to make the code
** run a little faster. For compiling on a Mac, you'll probably need
** to omit the -DHAVE_READLINE, the -lreadline, and the -lncurses options.
** The compilation could be simplified to just this:
**
** gcc -DSQLITE_ENABLE_VFSTRACE \
** shell.c test_vfstrace.c sqlite3.c -ldl -lpthread
**
** In this second example, all unnecessary options have been removed
** Note that since the code is now threadsafe, we had to add the -lpthread
** option to pull in the pthreads library.
**
** To cross-compile for windows using MinGW, a command like this might
** work:
**
** /opt/mingw/bin/i386-mingw32msvc-gcc -o sqlite3.exe -Os -I \
** -DSQLITE_THREADSAFE=0 -DSQLITE_ENABLE_VFSTRACE \
** shell.c test_vfstrace.c sqlite3.c
**
** Similar compiler commands will work on different systems. The key
** invariants are (1) you must have -DSQLITE_ENABLE_VFSTRACE so that
** the shell.c source file will know to include the -vfstrace command-line
** option and (2) you must compile and link the three source files
** shell,c, test_vfstrace.c, and sqlite3.c.
*/
//#include <stdlib.h>
//#include <string.h>
//#include "sqlite3.h"
 
/*
** An instance of this structure is attached to the each trace VFS to
** provide auxiliary information.
*/
//typedef struct vfstrace_info vfstrace_info;
class vfstrace_info {
public sqlite3_vfs pRootVfs; /* The underlying real VFS */
public smdxFunctionArg xOut;//int (*xOut)(const char*, void); /* Send output here */
public object pOutArg; /* First argument to xOut */
public string zVfsName; /* Name of this trace-VFS */
public sqlite3_vfs pTraceVfs; /* Pointer back to the trace VFS */
};
 
/*
** The sqlite3_file object for the trace VFS
*/
//typedef struct vfstrace_file vfstrace_file;
class vfstrace_file : sqlite3_file
{
//public sqlite3_file base; /* Base class. Must be first */
public vfstrace_info pInfo; /* The trace-VFS to which this file belongs */
public string zFName; /* Base name of the file */
public sqlite3_file pReal; /* The real underlying file */
};
 
/*
** Method declarations for vfstrace_file.
*/
//static int vfstraceClose(sqlite3_file);
//static int vfstraceRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
//static int vfstraceWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
//static int vfstraceTruncate(sqlite3_file*, sqlite3_int64 size);
//static int vfstraceSync(sqlite3_file*, int flags);
//static int vfstraceFileSize(sqlite3_file*, sqlite3_int64 pSize);
//static int vfstraceLock(sqlite3_file*, int);
//static int vfstraceUnlock(sqlite3_file*, int);
//static int vfstraceCheckReservedLock(sqlite3_file*, int );
//static int vfstraceFileControl(sqlite3_file*, int op, object pArg);
//static int vfstraceSectorSize(sqlite3_file);
//static int vfstraceDeviceCharacteristics(sqlite3_file);
//static int vfstraceShmLock(sqlite3_file*,int,int,int);
//static int vfstraceShmMap(sqlite3_file*,int,int,int, object volatile *);
//static void vfstraceShmBarrier(sqlite3_file);
//static int vfstraceShmUnmap(sqlite3_file*,int);
 
/*
** Method declarations for vfstrace_vfs.
*/
//static int vfstraceOpen(sqlite3_vfs*, string , sqlite3_file*, int , int );
//static int vfstraceDelete(sqlite3_vfs*, string zName, int syncDir);
//static int vfstraceAccess(sqlite3_vfs*, string zName, int flags, int );
//static int vfstraceFullPathname(sqlite3_vfs*, string zName, int, char );
//static void vfstraceDlOpen(sqlite3_vfs*, string zFilename);
//static void vfstraceDlError(sqlite3_vfs*, int nByte, string zErrMsg);
//static void (*vfstraceDlSym(sqlite3_vfs*,void*, string zSymbol))(void);
//static void vfstraceDlClose(sqlite3_vfs*, void);
//static int vfstraceRandomness(sqlite3_vfs*, int nByte, string zOut);
//static int vfstraceSleep(sqlite3_vfs*, int microseconds);
//static int vfstraceCurrentTime(sqlite3_vfs*, double);
//static int vfstraceGetLastError(sqlite3_vfs*, int, char);
//static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64);
//static int vfstraceSetSystemCall(sqlite3_vfs*,const char*, sqlite3_syscall_ptr);
//static sqlite3_syscall_ptr vfstraceGetSystemCall(sqlite3_vfs*, string );
//static string vfstraceNextSystemCall(sqlite3_vfs*, string zName);
 
/*
** Return a pointer to the tail of the pathname. Examples:
**
** /home/drh/xyzzy.txt . xyzzy.txt
** xyzzy.txt . xyzzy.txt
*/
static string fileTail(string z){
int i;
if( String.IsNullOrEmpty(z) ) return "";
i = z.Length - 1;// strlen( z ) - 1;
Debugger.Break();
//while( i>0 && z[i-1]!='/' ){ i--; }
//return &z[i];
return "";
}
 
/*
** Send trace output defined by zFormat and subsequent arguments.
*/
static void vfstrace_printf(
vfstrace_info pInfo,
string zFormat,
params object[]ap
){
//va_list ap;
string zMsg;
va_start(ap, zFormat);
zMsg = sqlite3_vmprintf(zFormat, ap);
va_end(ref ap);
Debugger.Break();
//pInfo.xOut( zMsg, pInfo.pOutArg );
//sqlite3_free(zMsg);
}
 
/*
** Convert value rc into a string and print it using zFormat. zFormat
** should have exactly one %s
*/
static void vfstrace_print_errcode(
vfstrace_info pInfo,
string zFormat,
int rc
){
StringBuilder zBuf = new StringBuilder(50);//char zBuf[50];
string zVal;
switch( rc ){
case SQLITE_OK: zVal = "SQLITE_OK"; break;
case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
case SQLITE_IOERR_READ: zVal = "SQLITE_IOERR_READ"; break;
case SQLITE_IOERR_SHORT_READ: zVal = "SQLITE_IOERR_SHORT_READ"; break;
case SQLITE_IOERR_WRITE: zVal = "SQLITE_IOERR_WRITE"; break;
case SQLITE_IOERR_FSYNC: zVal = "SQLITE_IOERR_FSYNC"; break;
case SQLITE_IOERR_DIR_FSYNC: zVal = "SQLITE_IOERR_DIR_FSYNC"; break;
case SQLITE_IOERR_TRUNCATE: zVal = "SQLITE_IOERR_TRUNCATE"; break;
case SQLITE_IOERR_FSTAT: zVal = "SQLITE_IOERR_FSTAT"; break;
case SQLITE_IOERR_UNLOCK: zVal = "SQLITE_IOERR_UNLOCK"; break;
case SQLITE_IOERR_RDLOCK: zVal = "SQLITE_IOERR_RDLOCK"; break;
case SQLITE_IOERR_DELETE: zVal = "SQLITE_IOERR_DELETE"; break;
case SQLITE_IOERR_BLOCKED: zVal = "SQLITE_IOERR_BLOCKED"; break;
case SQLITE_IOERR_NOMEM: zVal = "SQLITE_IOERR_NOMEM"; break;
case SQLITE_IOERR_ACCESS: zVal = "SQLITE_IOERR_ACCESS"; break;
case SQLITE_IOERR_CHECKRESERVEDLOCK:
zVal = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
case SQLITE_IOERR_LOCK: zVal = "SQLITE_IOERR_LOCK"; break;
case SQLITE_IOERR_CLOSE: zVal = "SQLITE_IOERR_CLOSE"; break;
case SQLITE_IOERR_DIR_CLOSE: zVal = "SQLITE_IOERR_DIR_CLOSE"; break;
case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
default: {
sqlite3_snprintf(zBuf.Capacity, zBuf, "%d", rc);
zVal = zBuf.ToString();
break;
}
}
vfstrace_printf(pInfo, zFormat, zVal);
}
 
/*
** Append to a buffer.
*/
static void strappend(string z, int pI, string zAppend){
int i = pI;
Debugger.Break();
//
//while( zAppend[0] ){ z[i++] = *(zAppend++); }
//z[i] = 0;
pI = i;
}
 
/*
** Close an vfstrace-file.
*/
static int vfstraceClose(sqlite3_file pFile){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
vfstrace_printf(pInfo, "%s.xClose(%s)", pInfo.zVfsName, p.zFName);
rc = p.pReal.pMethods.xClose(p.pReal);
vfstrace_print_errcode(pInfo, " . %s\n", rc);
if( rc==SQLITE_OK ){
//sqlite3_free(p._base.pMethods);
p.pMethods = null;//p.base.pMethods = 0;
}
return rc;
}
 
/*
** Read data from an vfstrace-file.
*/
static int vfstraceRead(
sqlite3_file pFile,
string zBuf,
int iAmt,
sqlite_int64 iOfst
){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc=0;
vfstrace_printf(pInfo, "%s.xRead(%s,n=%d,ofst=%lld)",
pInfo.zVfsName, p.zFName, iAmt, iOfst);
Debugger.Break();
// rc = p.pReal.pMethods.xRead(p.pReal, zBuf, iAmt, iOfst);
vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
 
/*
** Write data to an vfstrace-file.
*/
static int vfstraceWrite(
sqlite3_file pFile,
string zBuf,
int iAmt,
sqlite_int64 iOfst
){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc=0;
vfstrace_printf(pInfo, "%s.xWrite(%s,n=%d,ofst=%lld)",
pInfo.zVfsName, p.zFName, iAmt, iOfst);
Debugger.Break();//TODO
//rc = p.pReal.pMethods.xWrite( p.pReal, zBuf, iAmt, iOfst );
vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
 
/*
** Truncate an vfstrace-file.
*/
static int vfstraceTruncate(sqlite3_file pFile, sqlite_int64 size){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc=0;
vfstrace_printf(pInfo, "%s.xTruncate(%s,%lld)", pInfo.zVfsName, p.zFName,
size);
rc = p.pReal.pMethods.xTruncate(p.pReal, size);
vfstrace_printf(pInfo, " . %d\n", rc);
return rc;
}
 
/*
** Sync an vfstrace-file.
*/
static int vfstraceSync(sqlite3_file pFile, int flags){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
//int i;
StringBuilder zBuf = new StringBuilder(100);//char zBuf[100];
zBuf.Append( "|0" );// memcpy( zBuf, "|0", 3 );
if( (flags & SQLITE_SYNC_FULL )!=0) zBuf.Append( "|FULL");
else if( (flags & SQLITE_SYNC_NORMAL )!=0) zBuf.Append( "|NORMAL");
if( (flags & SQLITE_SYNC_DATAONLY ) !=0) zBuf.Append("|DATAONLY");
if ( ( flags & ~( SQLITE_SYNC_FULL | SQLITE_SYNC_DATAONLY ) ) != 0 )
{
//sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags);
Debugger.Break();//TODO
//zBuf.Append( sqlite3_printf( "|0x%x", flags ) );
}
Debugger.Break();//TODO
// vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo.zVfsName, p.zFName,
// zBuf.ToString().StartsWith(1));
rc = p.pReal.pMethods.xSync(p.pReal, flags);
vfstrace_printf(pInfo, " . %d\n", rc);
return rc;
}
 
/*
** Return the current file-size of an vfstrace-file.
*/
static int vfstraceFileSize(sqlite3_file pFile, sqlite_int64 pSize){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc=0;
vfstrace_printf(pInfo, "%s.xFileSize(%s)", pInfo.zVfsName, p.zFName);
Debugger.Break();//TODO
//rc = p.pReal.pMethods.xFileSize(p.pReal, pSize);
vfstrace_print_errcode(pInfo, " . %s,", rc);
vfstrace_printf(pInfo, " size=%lld\n", pSize);
return rc;
}
 
/*
** Return the name of a lock.
*/
static string lockName( int eLock )
{
string[] azLockNames = new string[] {
"NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
};
if ( eLock < 0 || eLock >= azLockNames.Length )//sizeof(azLockNames)/sizeof(azLockNames[0]) ){
{
return "???";
}
else
{
return azLockNames[eLock];
}
}
 
/*
** Lock an vfstrace-file.
*/
static int vfstraceLock(sqlite3_file pFile, int eLock){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
vfstrace_printf(pInfo, "%s.xLock(%s,%s)", pInfo.zVfsName, p.zFName,
lockName(eLock));
rc = p.pReal.pMethods.xLock(p.pReal, eLock);
vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
 
/*
** Unlock an vfstrace-file.
*/
static int vfstraceUnlock(sqlite3_file pFile, int eLock){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
vfstrace_printf(pInfo, "%s.xUnlock(%s,%s)", pInfo.zVfsName, p.zFName,
lockName(eLock));
rc = p.pReal.pMethods.xUnlock(p.pReal, eLock);
vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
 
/*
** Check if another file-handle holds a RESERVED lock on an vfstrace-file.
*/
static int vfstraceCheckReservedLock(sqlite3_file pFile, int pResOut){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc=0;
vfstrace_printf(pInfo, "%s.xCheckReservedLock(%s,%d)",
pInfo.zVfsName, p.zFName);
Debugger.Break();//TODO
//rc = p.pReal.pMethods.xCheckReservedLock(p.pReal, pResOut);
vfstrace_print_errcode(pInfo, " . %s", rc);
vfstrace_printf(pInfo, ", ref=%d\n", pResOut);
return rc;
}
 
/*
** File control method. For custom operations on an vfstrace-file.
*/
static int vfstraceFileControl(sqlite3_file pFile, int op, object pArg){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc=0;
Debugger.Break(); //TODO
//StringBuilder zBuf = new StringBuilder(100);
//string zOp;
//switch( op ){
// case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
// case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
// case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
// case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
// case SQLITE_FCNTL_SIZE_HINT: {
// sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
// *(sqlite3_int64)pArg);
// zOp = zBuf;
// break;
// }
// case SQLITE_FCNTL_CHUNK_SIZE: {
// sqlite3_snprintf(sizeof(zBuf), zBuf, "CHUNK_SIZE,%d", *(int)pArg);
// zOp = zBuf;
// break;
// }
// case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
// case SQLITE_FCNTL_SYNC_OMITTED: zOp = "SYNC_OMITTED"; break;
// case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
// default: {
// sqlite3_snprintf(zBuf.Capacity, zBuf, "%d", op);
// zOp = zBuf.ToString();
// break;
// }
//}
//vfstrace_printf(pInfo, "%s.xFileControl(%s,%s)",
// pInfo.zVfsName, p.zFName, zOp);
//rc = p.pReal.pMethods.xFileControl(p.pReal, op, pArg);
//vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
 
/*
** Return the sector-size in bytes for an vfstrace-file.
*/
static int vfstraceSectorSize(sqlite3_file pFile){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
vfstrace_printf(pInfo, "%s.xSectorSize(%s)", pInfo.zVfsName, p.zFName);
rc = p.pReal.pMethods.xSectorSize(p.pReal);
vfstrace_printf(pInfo, " . %d\n", rc);
return rc;
}
 
/*
** Return the device characteristic flags supported by an vfstrace-file.
*/
static int vfstraceDeviceCharacteristics(sqlite3_file pFile){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
vfstrace_printf(pInfo, "%s.xDeviceCharacteristics(%s)",
pInfo.zVfsName, p.zFName);
rc = p.pReal.pMethods.xDeviceCharacteristics(p.pReal);
vfstrace_printf(pInfo, " . 0x%08x\n", rc);
return rc;
}
 
/*
** Shared-memory operations.
*/
static int vfstraceShmLock(sqlite3_file pFile, int ofst, int n, int flags){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
StringBuilder zLck = new StringBuilder(100);
//int i = 0;
zLck.Append("|0");//memcpy( zLck, "|0", 3 );
if ( ( flags & SQLITE_SHM_UNLOCK ) != 0 )
zLck.Append( "|UNLOCK" );//strappend(zLck, &i, "|UNLOCK");
if ( ( flags & SQLITE_SHM_LOCK ) != 0 )
zLck.Append( "|LOCK" );//strappend(zLck, &i, "|LOCK");
if ( ( flags & SQLITE_SHM_SHARED ) != 0 )
zLck.Append( "|SHARED" );//strappend(zLck, &i, "|SHARED");
if ( ( flags & SQLITE_SHM_EXCLUSIVE ) != 0 )
zLck.Append( "|EXCLUSIVE" );//strappend(zLck, &i, "|EXCLUSIVE");
if ( ( flags & ~( 0xf ) ) != 0 )
{
Debugger.Break();//TODO
//zLck.Append( sqlite3_printf( "|0x%x", flags ) );//sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags);
}
//vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d,n=%d,%s)",
// pInfo.zVfsName, p.zFName, ofst, n, &zLck[1]);
rc = p.pReal.pMethods.xShmLock(p.pReal, ofst, n, flags);
vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
static int vfstraceShmMap(
sqlite3_file pFile,
int iRegion,
int szRegion,
int isWrite,
object pp
){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc=0;
vfstrace_printf(pInfo, "%s.xShmMap(%s,iRegion=%d,szRegion=%d,isWrite=%d,)",
pInfo.zVfsName, p.zFName, iRegion, szRegion, isWrite);
Debugger.Break();
//rc = p.pReal.pMethods.xShmMap( p.pReal, iRegion, szRegion, isWrite, pp );
vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
static void vfstraceShmBarrier(sqlite3_file pFile){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
vfstrace_printf(pInfo, "%s.xShmBarrier(%s)\n", pInfo.zVfsName, p.zFName);
p.pReal.pMethods.xShmBarrier(p.pReal);
}
static int vfstraceShmUnmap(sqlite3_file pFile, int delFlag){
vfstrace_file p = (vfstrace_file )pFile;
vfstrace_info pInfo = p.pInfo;
int rc;
vfstrace_printf(pInfo, "%s.xShmUnmap(%s,delFlag=%d)",
pInfo.zVfsName, p.zFName, delFlag);
rc = p.pReal.pMethods.xShmUnmap(p.pReal, delFlag);
vfstrace_print_errcode(pInfo, " . %s\n", rc);
return rc;
}
 
 
 
/*
** Open an vfstrace file handle.
*/
static int vfstraceOpen(
sqlite3_vfs pVfs,
string zName,
sqlite3_file pFile,
int flags,
int pOutFlags
){
int rc=0;
Debugger.Break(); //TODO
// vfstrace_file p = (vfstrace_file )pFile;
// vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
// sqlite3_vfs pRoot = pInfo.pRootVfs;
// p.pInfo = pInfo;
// p.zFName = zName ? fileTail(zName) : "<temp>";
// p.pReal = (sqlite3_file )&p[1];
// rc = pRoot.xOpen(pRoot, zName, p.pReal, flags, pOutFlags);
// vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
// pInfo.zVfsName, p.zFName, flags);
// if( p.pReal.pMethods ){
// sqlite3_io_methods pNew = new sqlite3_io_methods();//sqlite3_malloc( sizeof(*pNew) );
// sqlite3_io_methods pSub = p.pReal.pMethods;
// //memset(pNew, 0, sizeof(*pNew));
// pNew.iVersion = pSub.iVersion;
// pNew.xClose = vfstraceClose;
// pNew.xRead = vfstraceRead;
// pNew.xWrite = vfstraceWrite;
// pNew.xTruncate = vfstraceTruncate;
// pNew.xSync = vfstraceSync;
// pNew.xFileSize = vfstraceFileSize;
// pNew.xLock = vfstraceLock;
// pNew.xUnlock = vfstraceUnlock;
// pNew.xCheckReservedLock = vfstraceCheckReservedLock;
// pNew.xFileControl = vfstraceFileControl;
// pNew.xSectorSize = vfstraceSectorSize;
// pNew.xDeviceCharacteristics = vfstraceDeviceCharacteristics;
// if( pNew.iVersion>=2 ){
// pNew.xShmMap = pSub.xShmMap ? vfstraceShmMap : 0;
// pNew.xShmLock = pSub.xShmLock ? vfstraceShmLock : 0;
// pNew.xShmBarrier = pSub.xShmBarrier ? vfstraceShmBarrier : 0;
// pNew.xShmUnmap = pSub.xShmUnmap ? vfstraceShmUnmap : 0;
// }
// pFile.pMethods = pNew;
// }
// vfstrace_print_errcode(pInfo, " . %s", rc);
// if( pOutFlags ){
// vfstrace_printf(pInfo, ", refFlags=0x%x\n", pOutFlags);
// }else{
// vfstrace_printf(pInfo, "\n");
// }
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 vfstraceDelete( sqlite3_vfs pVfs, string zPath, int dirSync )
{
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
int rc;
vfstrace_printf( pInfo, "%s.xDelete(\"%s\",%d)",
pInfo.zVfsName, zPath, dirSync );
rc = pRoot.xDelete( pRoot, zPath, dirSync );
vfstrace_print_errcode( pInfo, " . %s\n", rc );
return rc;
}
 
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int vfstraceAccess(
sqlite3_vfs pVfs,
string zPath,
int flags,
int pResOut
){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
int rc;
vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
pInfo.zVfsName, zPath, flags);
rc = pRoot.xAccess( pRoot, zPath, flags, out pResOut );
vfstrace_print_errcode(pInfo, " . %s", rc);
vfstrace_printf(pInfo, ", ref=%d\n", pResOut);
return rc;
}
 
/*
** 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 vfstraceFullPathname(
sqlite3_vfs pVfs,
string zPath,
int nOut,
StringBuilder zOut
){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
int rc;
vfstrace_printf(pInfo, "%s.xFullPathname(\"%s\")",
pInfo.zVfsName, zPath);
rc = pRoot.xFullPathname(pRoot, zPath, nOut, zOut);
vfstrace_print_errcode(pInfo, " . %s", rc);
vfstrace_printf(pInfo, ", ref=\"%.*s\"\n", nOut, zOut);
return rc;
}
 
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void vfstraceDlOpen(sqlite3_vfs pVfs, string zPath){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
vfstrace_printf(pInfo, "%s.xDlOpen(\"%s\")\n", pInfo.zVfsName, zPath);
Debugger.Break();//TODO
//return pRoot.xDlOpen(pRoot, zPath);
return;
}
 
/*
** 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 vfstraceDlError(sqlite3_vfs pVfs, int nByte, string zErrMsg){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
vfstrace_printf(pInfo, "%s.xDlError(%d)", pInfo.zVfsName, nByte);
pRoot.xDlError(pRoot, nByte, zErrMsg);
vfstrace_printf(pInfo, " . \"%s\"", zErrMsg);
}
 
/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void vfstraceDlSym(sqlite3_vfs pVfs,object p,string zSym){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
vfstrace_printf(pInfo, "%s.xDlSym(\"%s\")\n", pInfo.zVfsName, zSym);
Debugger.Break();
//return pRoot.xDlSym(pRoot, p, zSym);
return;
}
 
/*
** Close the dynamic library handle pHandle.
*/
static void vfstraceDlClose(sqlite3_vfs pVfs, object pHandle){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo.zVfsName);
Debugger.Break();
// pRoot.xDlClose( pRoot, pHandle );
}
 
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int vfstraceRandomness(sqlite3_vfs pVfs, int nByte, byte[] zBufOut){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
vfstrace_printf(pInfo, "%s.xRandomness(%d)\n", pInfo.zVfsName, nByte);
return pRoot.xRandomness( pRoot, nByte, zBufOut );
}
 
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int vfstraceSleep(sqlite3_vfs pVfs, int nMicro){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
return pRoot.xSleep(pRoot, nMicro);
}
 
/*
** Return the current time as a Julian Day number in pTimeOut.
*/
static int vfstraceCurrentTime(sqlite3_vfs pVfs, double pTimeOut){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
return pRoot.xCurrentTime(pRoot, ref pTimeOut);
}
static int vfstraceCurrentTimeInt64(sqlite3_vfs pVfs, sqlite_int64 pTimeOut){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
return pRoot.xCurrentTimeInt64(pRoot, ref pTimeOut);
}
 
/*
** Return th3 emost recent error code and message
*/
static int vfstraceGetLastError(sqlite3_vfs pVfs, int iErr, string zErr){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
Debugger.Break();
//return pRoot.xGetLastError(pRoot, iErr, zErr);
return 0;
}
 
/*
** Override system calls.
*/
static int vfstraceSetSystemCall(
sqlite3_vfs pVfs,
string zName,
sqlite3_int64 pFunc //sqlite3_syscall_ptr pFunc
){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
return pRoot.xSetSystemCall(pRoot, zName, pFunc);
}
static sqlite3_int64 vfstraceGetSystemCall(//sqlite3_syscall_ptr vfstraceGetSystemCall(
sqlite3_vfs pVfs,
string zName
){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
Debugger.Break();
//return pRoot.xGetSystemCall(pRoot, zName);
return 0;
}
static string vfstraceNextSystemCall(sqlite3_vfs pVfs, string zName){
vfstrace_info pInfo = (vfstrace_info)pVfs.pAppData;
sqlite3_vfs pRoot = pInfo.pRootVfs;
Debugger.Break();
//return pRoot.xNextSystemCall(pRoot, zName);
return "";
}
 
 
/*
** Clients invoke this routine to construct a new trace-vfs shim.
**
** Return SQLITE_OK on success.
**
** SQLITE_NOMEM is returned in the case of a memory allocation error.
** SQLITE_NOTFOUND is returned if zOldVfsName does not exist.
*/
int vfstrace_register(
string zTraceName, /* Name of the newly constructed VFS */
string zOldVfsName, /* Name of the underlying VFS */
smdxFunction xOut,//int (*xOut)(const char*,void), /* Output routine. ex: fputs */
object pOutArg, /* 2nd argument to xOut. ex: stderr */
int makeDefault /* True to make the new VFS the default */
){
sqlite3_vfs pNew;
sqlite3_vfs pRoot;
vfstrace_info pInfo;
int nName;
int nByte;
 
Debugger.Break();//TODO
//pRoot = sqlite3_vfs_find(zOldVfsName);
//if( pRoot==null ) return SQLITE_NOTFOUND;
//nName = strlen(zTraceName);
////nByte = sizeof(*pNew) + sizeof(*pInfo) + nName + 1;
//pNew = new sqlite3_vfs();//sqlite3_malloc( nByte );
////if( pNew==0 ) return SQLITE_NOMEM;
////memset(pNew, 0, nByte);
//pInfo = new vfstrace_info();//( vfstrace_info ) & pNew[1];
//pNew.iVersion = pRoot.iVersion;
//pNew.szOsFile = pRoot.szOsFile + sizeof(vfstrace_file);
//pNew.mxPathname = pRoot.mxPathname;
////pNew.zName = (char)&pInfo[1];
//pNew.zName = zTraceName;//memcpy( (char)&pInfo[1], zTraceName, nName + 1 );
//pNew.pAppData = pInfo;
//pNew.xOpen = vfstraceOpen;
//pNew.xDelete = vfstraceDelete;
//pNew.xAccess = vfstraceAccess;
//pNew.xFullPathname = vfstraceFullPathname;
//pNew.xDlOpen = pRoot.xDlOpen==null ? null : vfstraceDlOpen;
//pNew.xDlError = pRoot.xDlError==null ? null : vfstraceDlError;
//pNew.xDlSym = pRoot.xDlSym==null ? null : vfstraceDlSym;
//pNew.xDlClose = pRoot.xDlClose==null ? null : vfstraceDlClose;
//pNew.xRandomness = vfstraceRandomness;
//pNew.xSleep = vfstraceSleep;
//pNew.xCurrentTime = vfstraceCurrentTime;
//pNew.xGetLastError = pRoot.xGetLastError == null ? (dxGetLastError)null : vfstraceGetLastError;
//if( pNew.iVersion>=2 ){
// pNew.xCurrentTimeInt64 = pRoot.xCurrentTimeInt64==null ? null :
// vfstraceCurrentTimeInt64;
// if( pNew.iVersion>=3 ){
// pNew.xSetSystemCall = pRoot.xSetSystemCall==null ? (dxSetSystemCall)null :
// vfstraceSetSystemCall;
// pNew.xGetSystemCall = pRoot.xGetSystemCall == null ? (dxGetSystemCall)null :
// vfstraceGetSystemCall;
// pNew.xNextSystemCall = pRoot.xNextSystemCall == null ? (dxNextSystemCall)null :
// vfstraceNextSystemCall;
// }
//}
//pInfo.pRootVfs = pRoot;
//pInfo.xOut = xOut;
//pInfo.pOutArg = pOutArg;
//pInfo.zVfsName = pNew.zName;
//pInfo.pTraceVfs = pNew;
//vfstrace_printf(pInfo, "%s.enabled_for(\"%s\")\n",
// pInfo.zVfsName, pRoot.zName);
//return sqlite3_vfs_register(pNew, makeDefault);
return 0;
}
}
#endif
}
/trunk/testfixture/src/test_wholenumber_c.cs
@@ -0,0 +1,372 @@
using System.Diagnostics;
using unsigned = System.UInt32;
using sqlite_int64 = System.Int64;
using sqlite3_int64 = System.Int64;
using sqlite3_value_int64 = System.Int64;
 
namespace Community.CsharpSqlite
{
#if TCLSH
using tcl.lang;
using sqlite3_stmt = Sqlite3.Vdbe;
using sqlite3_value = Sqlite3.Mem;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using ClientData = System.Object;
 
public partial class Sqlite3
{
/*
** 2011 April 02
**
** 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 implements a virtual table that returns the whole numbers
** between 1 and 4294967295, inclusive.
**
** Example:
**
** CREATE VIRTUAL TABLE nums USING wholenumber;
** SELECT value FROM nums WHERE value<10;
**
** Results in:
**
** 1 2 3 4 5 6 7 8 9
*/
//#include "sqlite3.h"
//#include <assert.h>
//#include <string.h>
 
#if !SQLITE_OMIT_VIRTUALTABLE
 
 
/* A wholenumber cursor object */
//typedef struct wholenumber_cursor wholenumber_cursor;
class wholenumber_cursor : sqlite3_vtab_cursor
{
//public sqlite3_vtab_cursor base; /* Base class - must be first */
public unsigned iValue; /* Current value */
public unsigned mxValue; /* Maximum value */
};
 
/* Methods for the wholenumber module */
static int wholenumberConnect(
sqlite3 db,
object pAux,
int argc, string[] argv,
out sqlite3_vtab ppVtab,
out string pzErr
)
{
sqlite3_vtab pNew;
pNew = ppVtab = new sqlite3_vtab();//sqlite3_malloc( sizeof(*pNew) );
//if ( pNew == null )
// return SQLITE_NOMEM;
sqlite3_declare_vtab( db, "CREATE TABLE x(value)" );
//memset(pNew, 0, sizeof(*pNew));
pzErr = "";
return SQLITE_OK;
}
/* Note that for this virtual table, the xCreate and xConnect
** methods are identical. */
 
static int wholenumberDisconnect( ref object pVtab )
{
pVtab = null;// sqlite3_free( pVtab );
return SQLITE_OK;
}
/* The xDisconnect and xDestroy methods are also the same */
 
 
/*
** Open a new wholenumber cursor.
*/
static int wholenumberOpen( sqlite3_vtab p, out sqlite3_vtab_cursor ppCursor )
{
wholenumber_cursor pCur;
pCur = new wholenumber_cursor();//sqlite3_malloc( sizeof(*pCur) );
//if ( pCur == null )
// return SQLITE_NOMEM;
//memset(pCur, 0, sizeof(*pCur));
ppCursor = pCur;//.base;
return SQLITE_OK;
}
 
/*
** Close a wholenumber cursor.
*/
static int wholenumberClose( ref sqlite3_vtab_cursor cur )
{
cur = null;// sqlite3_free( ref cur );
return SQLITE_OK;
}
 
 
/*
** Advance a cursor to its next row of output
*/
static int wholenumberNext( sqlite3_vtab_cursor cur )
{
wholenumber_cursor pCur = (wholenumber_cursor)cur;
pCur.iValue++;
return SQLITE_OK;
}
 
/*
** Return the value associated with a wholenumber.
*/
static int wholenumberColumn(
sqlite3_vtab_cursor cur,
sqlite3_context ctx,
int i
)
{
wholenumber_cursor pCur = (wholenumber_cursor)cur;
sqlite3_result_int64( ctx, pCur.iValue );
return SQLITE_OK;
}
 
/*
** The rowid.
*/
static int wholenumberRowid( sqlite3_vtab_cursor cur, out sqlite_int64 pRowid )
{
wholenumber_cursor pCur = (wholenumber_cursor)cur;
pRowid = pCur.iValue;
return SQLITE_OK;
}
 
/*
** When the wholenumber_cursor.rLimit value is 0 or less, that is a signal
** that the cursor has nothing more to output.
*/
static int wholenumberEof( sqlite3_vtab_cursor cur )
{
wholenumber_cursor pCur = (wholenumber_cursor)cur;
return ( pCur.iValue > pCur.mxValue || pCur.iValue == 0 ) ? 1 : 0;
}
 
/*
** Called to "rewind" a cursor back to the beginning so that
** it starts its output over again. Always called at least once
** prior to any wholenumberColumn, wholenumberRowid, or wholenumberEof call.
**
** idxNum Constraints
** ------ ---------------------
** 0 (none)
** 1 value > $argv0
** 2 value >= $argv0
** 4 value < $argv0
** 8 value <= $argv0
**
** 5 value > $argv0 AND value < $argv1
** 6 value >= $argv0 AND value < $argv1
** 9 value > $argv0 AND value <= $argv1
** 10 value >= $argv0 AND value <= $argv1
*/
static int wholenumberFilter(
sqlite3_vtab_cursor pVtabCursor,
int idxNum, string idxStr,
int argc, sqlite3_value[] argv
)
{
wholenumber_cursor pCur = (wholenumber_cursor)pVtabCursor;
sqlite3_int64 v;
int i = 0;
pCur.iValue = 1;
pCur.mxValue = 0xffffffff; /* 4294967295 */
if ( ( idxNum & 3 ) != 0 )
{
v = sqlite3_value_int64( argv[0] ) + ( idxNum & 1 );
if ( v > pCur.iValue && v <= pCur.mxValue )
pCur.iValue = (uint)v;
i++;
}
if ( ( idxNum & 12 ) != 0 )
{
v = sqlite3_value_int64( argv[i] ) - ( ( idxNum >> 2 ) & 1 );
if ( v >= pCur.iValue && v < pCur.mxValue )
pCur.mxValue = (uint)v;
}
return SQLITE_OK;
}
 
/*
** Search for terms of these forms:
**
** (1) value > $value
** (2) value >= $value
** (4) value < $value
** (8) value <= $value
**
** idxNum is an ORed combination of 1 or 2 with 4 or 8.
*/
static int wholenumberBestIndex(
sqlite3_vtab vtab,
ref sqlite3_index_info pIdxInfo
)
{
int i;
int idxNum = 0;
int argvIdx = 1;
int ltIdx = -1;
int gtIdx = -1;
sqlite3_index_constraint pConstraint;
//pConstraint = pIdxInfo.aConstraint;
for ( i = 0; i < pIdxInfo.nConstraint; i++ )//, pConstraint++)
{
pConstraint = pIdxInfo.aConstraint[i];
if ( pConstraint.usable == false )
continue;
if ( ( idxNum & 3 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_GT )
{
idxNum |= 1;
ltIdx = i;
}
if ( ( idxNum & 3 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_GE )
{
idxNum |= 2;
ltIdx = i;
}
if ( ( idxNum & 12 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_LT )
{
idxNum |= 4;
gtIdx = i;
}
if ( ( idxNum & 12 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_LE )
{
idxNum |= 8;
gtIdx = i;
}
}
pIdxInfo.idxNum = idxNum;
if ( ltIdx >= 0 )
{
pIdxInfo.aConstraintUsage[ltIdx].argvIndex = argvIdx++;
pIdxInfo.aConstraintUsage[ltIdx].omit = true;
}
if ( gtIdx >= 0 )
{
pIdxInfo.aConstraintUsage[gtIdx].argvIndex = argvIdx;
pIdxInfo.aConstraintUsage[gtIdx].omit = true;
}
if ( pIdxInfo.nOrderBy == 1
&& pIdxInfo.aOrderBy[0].desc == false
)
{
pIdxInfo.orderByConsumed = true;
}
pIdxInfo.estimatedCost = (double)1;
return SQLITE_OK;
}
 
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
*/
static sqlite3_module wholenumberModule = new sqlite3_module(
2, /* iVersion */
(smdxCreateConnect)wholenumberConnect,
(smdxCreateConnect)wholenumberConnect,
(smdxBestIndex)wholenumberBestIndex,
(smdxDisconnect)wholenumberDisconnect,
(smdxDestroy)wholenumberDisconnect,
(smdxOpen)wholenumberOpen, /* xOpen - open a cursor */
(smdxClose)wholenumberClose, /* xClose - close a cursor */
(smdxFilter)wholenumberFilter, /* xFilter - configure scan constraints */
(smdxNext)wholenumberNext, /* xNext - advance a cursor */
(smdxEof)wholenumberEof, /* xEof - check for end of scan */
(smdxColumn)wholenumberColumn, /* xColumn - read data */
(smdxRowid)wholenumberRowid, /* xRowid - read data */
null, /* xUpdate */
null, /* xBegin */
null, /* xSync */
null, /* xCommit */
null, /* xRollback */
null, /* xFindMethod */
null, /* xRename */
/* The methods above are in version 1 of the sqlite_module object. Those
** below are for version 2 and greater. */
null,
null,
null
);
 
#endif //* SQLITE_OMIT_VIRTUALTABLE */
 
 
/*
** Register the wholenumber virtual table
*/
static int wholenumber_register( sqlite3 db )
{
int rc = SQLITE_OK;
#if !SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module( db, "wholenumber", wholenumberModule, null );
#endif
return rc;
}
 
#if SQLITE_TEST
//#include <tcl.h>
/*
** Decode a pointer to an sqlite3 object.
*/
//extern int getDbPointer(Tcl_Interp interp, string zA, sqlite3 **ppDb);
 
/*
** Register the echo virtual table module.
*/
static int register_wholenumber_module(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj[] objv /* Command arguments */
)
{
sqlite3 db = null;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "DB" );
return TCL.TCL_ERROR;
}
if ( getDbPointer( interp, TCL.Tcl_GetString( objv[1] ), out db ) != 0 )
return TCL.TCL_ERROR;
wholenumber_register( db );
return TCL.TCL_OK;
}
 
 
//static class _aObjCmd {
// public string zName;
// public Tcl_ObjCmdProc xProc;
// public object clientData;
//}
/*
** Register commands with the TCL interpreter.
*/
static public int Sqlitetestwholenumber_Init( Tcl_Interp interp )
{
_aObjCmd[] aObjCmd = new _aObjCmd[] {
new _aObjCmd( "register_wholenumber_module", register_wholenumber_module, 0 ),
};
int i;
for ( i = 0; i < aObjCmd.Length; i++ )
{//sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
TCL.Tcl_CreateObjCommand( interp, aObjCmd[i].zName,
aObjCmd[i].xProc, aObjCmd[i].clientData, null );
}
return TCL.TCL_OK;
}
 
#endif //* SQLITE_TEST */
}
#endif
}
/trunk/testfixture/src/testfixture.cs
@@ -0,0 +1,573 @@
using System;
using System.Text;
using Community.CsharpSqlite;
using tcl.lang;
using ClientData = System.Object;
using Tcl_Interp = tcl.lang.Interp;
using Tcl_Obj = tcl.lang.TclObject;
using System.IO;
using System.Diagnostics;
 
 
class Testing
{
/*
** 2009 July 17
**
** 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 to implement the "sqlite" test harness
** which runs TCL commands for testing the C#-SQLite port.
**
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
** C#-SQLite is an independent reimplementation of the SQLite software library
**
*************************************************************************
*/
public static void Main( string[] args )
{
// Array of command-line argument strings.
{
string fileName = null;
 
// Create the interpreter. This will also create the built-in
// Tcl commands.
 
Interp interp = new Interp();
 
// Make command-line arguments available in the Tcl variables "argc"
// and "argv". If the first argument doesn't start with a "-" then
// strip it off and use it as the name of a script file to process.
// We also set the argv0 and TCL.Tcl_interactive vars here.
 
if ( ( args.Length > 0 ) && !( args[0].StartsWith( "-" ) ) )
{
fileName = args[0];
}
 
TclObject argv = TclList.newInstance();
argv.preserve();
try
{
int i = 0;
int argc = args.Length;
if ( (System.Object)fileName == null )
{
interp.setVar( "argv0", "tcl.lang.Shell", TCL.VarFlag.GLOBAL_ONLY );
interp.setVar( "tcl_interactive", "1", TCL.VarFlag.GLOBAL_ONLY );
}
else
{
interp.setVar( "argv0", fileName, TCL.VarFlag.GLOBAL_ONLY );
interp.setVar( "tcl_interactive", "0", TCL.VarFlag.GLOBAL_ONLY );
i++;
argc--;
}
for ( ; i < args.Length; i++ )
{
TclList.append( interp, argv, TclString.newInstance( args[i] ) );
}
interp.setVar( "argv", argv, TCL.VarFlag.GLOBAL_ONLY );
interp.setVar( "argc", System.Convert.ToString( argc ), TCL.VarFlag.GLOBAL_ONLY );
}
catch ( TclException e )
{
throw new TclRuntimeError( "unexpected TclException: " + e.Message );
}
finally
{
argv.release();
}
 
init_all( interp );
TCL.Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, null );
 
 
// Normally we would do application specific initialization here.
// However, that feature is not currently supported.
// If a script file was specified then just source that file
// and quit.
 
Console.WriteLine( " C#-SQLite version " + Sqlite3.sqlite3_version );
Console.WriteLine( "An independent reimplementation of the SQLite software library" );
Console.WriteLine( "==============================================================" );
Console.WriteLine( "" );
 
if ( (System.Object)fileName != null )
{
try
{
interp.evalFile( fileName );
}
catch ( TclException e )
{
TCL.CompletionCode code = e.getCompletionCode();
if ( code == TCL.CompletionCode.RETURN )
{
code = interp.updateReturnInfo();
if ( code != TCL.CompletionCode.OK )
{
System.Console.Error.WriteLine( "command returned bad code: " + code );
if ( tcl.lang.ConsoleThread.debug )
System.Diagnostics.Debug.WriteLine( "command returned bad code: " + code );
}
}
else if ( code == TCL.CompletionCode.ERROR )
{
System.Console.Error.WriteLine( interp.getResult().ToString() );
if ( tcl.lang.ConsoleThread.debug )
System.Diagnostics.Debug.WriteLine( interp.getResult().ToString() );
System.Diagnostics.Debug.Assert( false, interp.getResult().ToString() );
}
else if ( code != TCL.CompletionCode.EXIT )
{
System.Console.Error.WriteLine( "command returned bad code: " + code );
if ( tcl.lang.ConsoleThread.debug )
System.Diagnostics.Debug.WriteLine( "command returned bad code: " + code );
}
}
 
// Note that if the above interp.evalFile() returns the main
// thread will exit. This may bring down the VM and stop
// the execution of Tcl.
//
// If the script needs to handle events, it must call
// vwait or do something similar.
//
// Note that the script can create AWT widgets. This will
// start an AWT event handling thread and keep the VM up. However,
// the interpreter thread (the same as the main thread) would
// have exited and no Tcl scripts can be executed.
 
interp.dispose();
Sqlite3.sqlite3_shutdown();
 
System.Environment.Exit( 0 );
}
 
if ( (System.Object)fileName == null )
{
// We are running in interactive mode. Start the ConsoleThread
// that loops, grabbing stdin and passing it to the interp.
 
ConsoleThread consoleThread = new ConsoleThread( interp );
consoleThread.IsBackground = true;
consoleThread.Start();
 
// Loop forever to handle user input events in the command line.
 
Notifier notifier = interp.getNotifier();
while ( true )
{
// process events until "exit" is called.
 
notifier.doOneEvent( TCL.ALL_EVENTS );
}
}
}
}
#if SQLITE_TEST
//static void init_all(Tcl_Interp );
static int init_all_cmd(
ClientData cd,
Tcl_Interp interp,
int objc,
Tcl_Obj[] objv
)
{
Tcl_Interp slave;
if ( objc != 2 )
{
TCL.Tcl_WrongNumArgs( interp, 1, objv, "SLAVE" );
return TCL.TCL_ERROR;
}
 
slave = TCL.Tcl_GetSlave( interp, TCL.Tcl_GetString( objv[1] ) );
if ( slave == null )
{
return TCL.TCL_ERROR;
}
 
init_all( slave );
return TCL.TCL_OK;
}
#endif
// Setup SQLIte specific object for routines
static void init_all( Interp interp )
{
Sqlite3.Sqlite3_Init( interp );
Sqlite3.Sqlitetestbackup_Init( interp );
Sqlite3.Sqlitetestfuzzer_Init( interp );
Sqlite3.Sqliteconfig_Init( interp );
Sqlite3.Sqlitetest_autoext_Init( interp );
Sqlite3.Sqlitetest_func_Init( interp );
Sqlite3.Sqlitetest_hexio_Init( interp );
Sqlite3.Sqlitetest_malloc_Init( interp );
Sqlite3.Sqlitetest_mutex_Init( interp );
Sqlite3.Sqlitetestintarray_Init( interp );
Sqlite3.Sqlitetestschema_Init( interp );
Sqlite3.SqlitetestStat_Init( interp );
Sqlite3.Sqlitetesttclvar_Init( interp );
Sqlite3.Sqlitetestwholenumber_Init( interp );
Sqlite3.Sqlitetest1_Init( interp );
Sqlite3.Sqlitetest2_Init( interp );
Sqlite3.Sqlitetest3_Init( interp );
Sqlite3.Sqlitetest8_Init( interp );
Sqlite3.Sqlitetest9_Init( interp );
Sqlite3.Md5_Init( interp );
}
 
}
 
namespace tcl.lang
{
class ConsoleThread : SupportClass.ThreadClass
{
private class AnonymousClassTclEvent : TclEvent
{
public AnonymousClassTclEvent( string command, ConsoleThread enclosingInstance )
{
InitBlock( command, enclosingInstance );
}
private void InitBlock( string command, ConsoleThread enclosingInstance )
{
this.command = command;
this.enclosingInstance = enclosingInstance;
}
private string command;
private ConsoleThread enclosingInstance;
public ConsoleThread Enclosing_Instance
{
get
{
return enclosingInstance;
}
 
}
public override int processEvent( int flags )
{
 
// See if the command is a complete Tcl command
 
if ( Interp.commandComplete( command ) )
{
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "line was a complete command" );
}
 
bool eval_exception = true;
TclObject commandObj = TclString.newInstance( command );
 
try
{
commandObj.preserve();
Enclosing_Instance.interp.recordAndEval( commandObj, 0 );
eval_exception = false;
}
catch ( TclException e )
{
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "eval returned exceptional condition" );
}
 
TCL.CompletionCode code = e.getCompletionCode();
switch ( code )
{
 
case TCL.CompletionCode.ERROR:
 
Enclosing_Instance.putLine( Enclosing_Instance.err, Enclosing_Instance.interp.getResult().ToString() );
break;
 
case TCL.CompletionCode.BREAK:
Enclosing_Instance.putLine( Enclosing_Instance.err, "invoked \"break\" outside of a loop" );
break;
 
case TCL.CompletionCode.CONTINUE:
Enclosing_Instance.putLine( Enclosing_Instance.err, "invoked \"continue\" outside of a loop" );
break;
 
default:
Enclosing_Instance.putLine( Enclosing_Instance.err, "command returned bad code: " + code );
break;
 
}
}
finally
{
commandObj.release();
}
 
if ( !eval_exception )
{
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "eval returned normally" );
}
 
 
string evalResult = Enclosing_Instance.interp.getResult().ToString();
 
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "eval result was \"" + evalResult + "\"" );
}
 
if ( evalResult.Length > 0 )
{
Enclosing_Instance.putLine( Enclosing_Instance.out_Renamed, evalResult );
}
}
 
// Empty out the incoming command buffer
Enclosing_Instance.sbuf.Length = 0;
 
// See if the user set a custom shell prompt for the next command
 
TclObject prompt;
 
try
{
prompt = Enclosing_Instance.interp.getVar( "tcl_prompt1", TCL.VarFlag.GLOBAL_ONLY );
}
catch ( TclException e )
{
prompt = null;
}
if ( prompt != null )
{
try
{
 
Enclosing_Instance.interp.eval( prompt.ToString(), TCL.EVAL_GLOBAL );
}
catch ( TclException e )
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "% " );
}
}
else
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "% " );
}
 
return 1;
}
else
{
// Interp.commandComplete() returned false
 
if ( tcl.lang.ConsoleThread.debug )
{
WriteLine( "line was not a complete command" );
}
 
// We don't have a complete command yet. Print out a level 2
// prompt message and wait for further inputs.
 
TclObject prompt;
 
try
{
prompt = Enclosing_Instance.interp.getVar( "tcl_prompt2", TCL.VarFlag.GLOBAL_ONLY );
}
catch ( TclException )
{
prompt = null;
}
if ( prompt != null )
{
try
{
 
Enclosing_Instance.interp.eval( prompt.ToString(), TCL.EVAL_GLOBAL );
}
catch ( TclException e )
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "" );
}
}
else
{
Enclosing_Instance.put( Enclosing_Instance.out_Renamed, "" );
}
 
return 1;
}
} // end processEvent method
}
 
// Interpreter associated with this console thread.
 
internal Interp interp;
 
// Collect the user input in this buffer until it forms a complete Tcl
// command.
 
internal StringBuilder sbuf;
 
// Used to for interactive input/output
 
private Channel out_Renamed;
private Channel err;
 
// set to true to get extra debug output
public static bool debug = true;
 
// used to keep track of wether or not System.in.available() works
private static bool sysInAvailableWorks = false;
 
internal ConsoleThread( Interp i )
{
Name = "ConsoleThread";
interp = i;
sbuf = new StringBuilder( 100 );
 
Debugger.Break();//TODO
//out_Renamed = Tcl_IO.getStdChannel( StdChannel.STDOUT );
//err = TCL.TclIO.getStdChannel( StdChannel.STDERR );
}
override public void Run()
{
if ( debug )
{
WriteLine( "entered ConsoleThread run() method" );
}
 
 
put( out_Renamed, "% " );
 
while ( true )
{
// Loop forever to collect user inputs in a StringBuffer.
// When we have a complete command, then execute it and print
// out the results.
//
// The loop is broken under two conditions: (1) when EOF is
// received inside getLine(). (2) when the "exit" command is
// executed in the script.
 
getLine();
string command = sbuf.ToString();
 
if ( debug )
{
WriteLine( "got line from console" );
WriteLine( "\"" + command + "\"" );
}
 
// When interacting with the interpreter, one must
// be careful to never call a Tcl method from
// outside of the event loop thread. If we did
// something like just call interp.eval() it
// could crash the whole process because two
// threads might write over each other.
 
// The only safe way to interact with Tcl is
// to create an event and add it to the thread
// safe event queue.
 
AnonymousClassTclEvent Tevent = new AnonymousClassTclEvent( command, this ); // end TclEvent innerclass
 
// Add the event to the thread safe event queue
interp.getNotifier().queueEvent( Tevent, TCL.QUEUE_TAIL );
 
// Tell this thread to wait until the event has been processed.
Tevent.sync();
}
}
private static void WriteLine( string s )
{
System.Console.Out.WriteLine( s );
if ( debug )
System.Diagnostics.Debug.WriteLine( s );
}
private void getLine()
{
sbuf.Append( Console.In.ReadLine() );
}
private void putLine( Channel channel, string s )
// The String to print.
{
try
{
channel.write( interp, s );
channel.write( interp, "\n" );
channel.flush( interp );
}
catch ( IOException ex )
{
System.Console.Error.WriteLine( "IOException in Shell.putLine()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
catch ( TclException ex )
{
System.Console.Error.WriteLine( "TclException in Shell.putLine()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
}
private void put( Channel channel, string s )
// The String to print.
{
try
{
channel.write( interp, s );
channel.flush( interp );
}
catch ( IOException ex )
{
System.Console.Error.WriteLine( "IOException in Shell.put()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
catch ( TclException ex )
{
System.Console.Error.WriteLine( "TclException in Shell.put()" );
SupportClass.WriteStackTrace( ex, System.Console.Error );
}
}
static ConsoleThread()
{
{
try
{
// There is no way to tell whether System.in will block AWT
// threads, so we assume it does block if we can use
// System.in.available().
 
long available = 0;
// HACK ATK
// available = System.Console.In.Length - System.Console.In.Position;
int generatedAux5 = (int)available;
sysInAvailableWorks = true;
}
catch ( System.Exception e )
{
// If System.in.available() causes an exception -- it's probably
// no supported on this platform (e.g. MS Java SDK). We assume
// sysInAvailableWorks is false and let the user suffer ...
}
 
// Sun's JDK 1.2 on Windows systems is screwed up, it does not
// echo chars to the console unless blocking IO is used.
// For this reason we need to use blocking IO under Windows.
 
if ( Util.Windows )
{
sysInAvailableWorks = false;
}
if ( debug )
{
WriteLine( "sysInAvailableWorks = " + sysInAvailableWorks );
}
}
}
} // end of class ConsoleThread
}
/trunk/testfixture/testfixture.csproj
@@ -0,0 +1,2399 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Community.Data.SQLite</RootNamespace>
<AssemblyName>Testfixture</AssemblyName>
<StartupObject>Testing</StartupObject>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkSubset>
</TargetFrameworkSubset>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRUE _MSC_VER WIN32 NET_35 SQLITE_ASCII SQLITE_DEBUG SQLITE_DISABLE_LFS SQLITE_ENABLE_COLUMN_METADATA SQLITE_HAS_CODEC SQLITE_MUTEX_W32 SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_THREADSAFE SQLITE_TEST SQLITE_USE_URI SQLITE_POOL_MEM SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_ENABLE_STAT2 VDBE_PROFILE_OFF TCLSH</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;DEBUG;TRUE WIN32 _MSC_VER SQLITE_ASCII SQLITE_DEBUG SQLITE_DISABLE_LFS SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_MUTEX_OMIT SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_VIRTUALTABLE SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_SYSTEM_MALLOC SQLITE_TEST VDBE_PROFILE_OFF</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRUE _MSC_VER WIN32 NET_35 SQLITE_ASCII SQLITE_DEBUG SQLITE_DISABLE_LFS SQLITE_ENABLE_COLUMN_METADATA SQLITE_HAS_CODEC SQLITE_MUTEX_W32 SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_THREADSAFE SQLITE_TEST SQLITE_USE_URI SQLITE_POOL_MEM SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_ENABLE_STAT2 VDBE_PROFILE_OFF TCLSH</DefineConstants>
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;DEBUG;TRUE WIN32 _MSC_VER SQLITE_ASCII SQLITE_DEBUG SQLITE_DISABLE_LFS SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_MUTEX_OMIT SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_VIRTUALTABLE SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_SYSTEM_MALLOC SQLITE_TEST VDBE_PROFILE_OFF</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRUE _MSC_VER WIN32 NET_35 SQLITE_ASCII SQLITE_DEBUG SQLITE_DISABLE_LFS SQLITE_ENABLE_COLUMN_METADATA SQLITE_HAS_CODEC SQLITE_MUTEX_W32 SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_THREADSAFE SQLITE_TEST SQLITE_USE_URI SQLITE_POOL_MEM SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_ENABLE_STAT2 VDBE_PROFILE_OFF TCLSH</DefineConstants>
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;DEBUG;TRUE WIN32 _MSC_VER SQLITE_ASCII SQLITE_DEBUG SQLITE_DISABLE_LFS SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_MUTEX_OMIT SQLITE_OMIT_AUTHORIZATION SQLITE_OMIT_DEPRECATED SQLITE_OMIT_GET_TABLE SQLITE_OMIT_INCRBLOB SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_SHARED_CACHE SQLITE_OMIT_UTF16 SQLITE_OMIT_VIRTUALTABLE SQLITE_OMIT_WAL SQLITE_OS_WIN SQLITE_SYSTEM_MALLOC SQLITE_TEST VDBE_PROFILE_OFF</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Management" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Community.CsharpSqlite\src\alter_c.cs">
<Link>Community.CsharpSqlite\alter_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\analyze_c.cs">
<Link>Community.CsharpSqlite\analyze_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\attach_c.cs">
<Link>Community.CsharpSqlite\attach_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\auth_c.cs">
<Link>Community.CsharpSqlite\auth_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\backup_c.cs">
<Link>Community.CsharpSqlite\backup_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\bitvec_c.cs">
<Link>Community.CsharpSqlite\bitvec_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\btmutex_c.cs">
<Link>Community.CsharpSqlite\btmutex_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\btreeInt_h.cs">
<Link>Community.CsharpSqlite\BtreeInt_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\btree_c.cs">
<Link>Community.CsharpSqlite\btree_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\btree_h.cs">
<Link>Community.CsharpSqlite\btree_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\build_c.cs">
<Link>Community.CsharpSqlite\build_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\callback_c.cs">
<Link>Community.CsharpSqlite\callback_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\complete_c.cs">
<Link>Community.CsharpSqlite\complete_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\crypto.cs">
<Link>Community.CsharpSqlite\crypto.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\ctime_c.cs">
<Link>Community.CsharpSqlite\ctime_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\date_c.cs">
<Link>Community.CsharpSqlite\date_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\Delegates.cs">
<Link>Community.CsharpSqlite\Delegates.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\delete_c.cs">
<Link>Community.CsharpSqlite\delete_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\expr_c.cs">
<Link>Community.CsharpSqlite\expr_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\fault_c.cs">
<Link>Community.CsharpSqlite\fault_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\fkey_c.cs">
<Link>Community.CsharpSqlite\fkey_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\func_c.cs">
<Link>Community.CsharpSqlite\func_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\global_c.cs">
<Link>Community.CsharpSqlite\global_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\hash_c.cs">
<Link>Community.CsharpSqlite\hash_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\Hash_h.cs">
<Link>Community.CsharpSqlite\Hash_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\hwtime_c.cs">
<Link>Community.CsharpSqlite\hwtime_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\insert_c.cs">
<Link>Community.CsharpSqlite\insert_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\journal_c.cs">
<Link>Community.CsharpSqlite\journal_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\keywordhash_h.cs">
<Link>Community.CsharpSqlite\keywordhash_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\legacy_c.cs">
<Link>Community.CsharpSqlite\legacy_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\loadext_c.cs">
<Link>Community.CsharpSqlite\loadext_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\main_c.cs">
<Link>Community.CsharpSqlite\main_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\malloc_c.cs">
<Link>Community.CsharpSqlite\malloc_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\memjournal_c.cs">
<Link>Community.CsharpSqlite\memjournal_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\mem_Pool.cs">
<Link>Community.CsharpSqlite\mem_Pool.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\mutex_c.cs">
<Link>Community.CsharpSqlite\mutex_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\mutex_h.cs">
<Link>Community.CsharpSqlite\mutex_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\mutex_noop_c.cs">
<Link>Community.CsharpSqlite\mutex_noop_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\mutex_w32.cs">
<Link>Community.CsharpSqlite\mutex_w32.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\opcodes_c.cs">
<Link>Community.CsharpSqlite\opcodes_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\opcodes_h.cs">
<Link>Community.CsharpSqlite\opcodes_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\os_c.cs">
<Link>Community.CsharpSqlite\os_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\os_common_h.cs">
<Link>Community.CsharpSqlite\os_common_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\os_h.cs">
<Link>Community.CsharpSqlite\os_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\os_win_c.cs">
<Link>Community.CsharpSqlite\os_win_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\pager_c.cs">
<Link>Community.CsharpSqlite\pager_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\pager_h.cs">
<Link>Community.CsharpSqlite\pager_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\parse_c.cs">
<Link>Community.CsharpSqlite\parse_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\parse_h.cs">
<Link>Community.CsharpSqlite\parse_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\pcache1_c.cs">
<Link>Community.CsharpSqlite\pcache1_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\pcache_c.cs">
<Link>Community.CsharpSqlite\pcache_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\pcache_h.cs">
<Link>Community.CsharpSqlite\pcache_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\pragma_c.cs">
<Link>Community.CsharpSqlite\pragma_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\prepare_c.cs">
<Link>Community.CsharpSqlite\prepare_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\printf_c.cs">
<Link>Community.CsharpSqlite\printf_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\random_c.cs">
<Link>Community.CsharpSqlite\random_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\resolve_c.cs">
<Link>Community.CsharpSqlite\resolve_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\rowset_c.cs">
<Link>Community.CsharpSqlite\rowset_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\select_c.cs">
<Link>Community.CsharpSqlite\select_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\sqlite3_h.cs">
<Link>Community.CsharpSqlite\sqlite3_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\sqliteInt_h.cs">
<Link>Community.CsharpSqlite\sqliteInt_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\sqliteLimit_h.cs">
<Link>Community.CsharpSqlite\sqliteLimit_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\status_c.cs">
<Link>Community.CsharpSqlite\status_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\table_c.cs">
<Link>Community.CsharpSqlite\table_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\tokenize_c.cs">
<Link>Community.CsharpSqlite\tokenize_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\trigger_c.cs">
<Link>Community.CsharpSqlite\trigger_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\update_c.cs">
<Link>Community.CsharpSqlite\update_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\utf_c.cs">
<Link>Community.CsharpSqlite\utf_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\util_c.cs">
<Link>Community.CsharpSqlite\util_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vacuum_c.cs">
<Link>Community.CsharpSqlite\vacuum_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbeapi_c.cs">
<Link>Community.CsharpSqlite\vdbeapi_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbeaux_c.cs">
<Link>Community.CsharpSqlite\vdbeaux_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbeblob_c.cs">
<Link>Community.CsharpSqlite\vdbeblob_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbeInt_h.cs">
<Link>Community.CsharpSqlite\vdbeInt_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbemem_c.cs">
<Link>Community.CsharpSqlite\vdbemem_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbetrace_c.cs">
<Link>Community.CsharpSqlite\vdbetrace_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbe_c.cs">
<Link>Community.CsharpSqlite\vdbe_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vdbe_h.cs">
<Link>Community.CsharpSqlite\vdbe_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\vtab_c.cs">
<Link>Community.CsharpSqlite\vtab_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\walker_c.cs">
<Link>Community.CsharpSqlite\walker_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\wal_c.cs">
<Link>Community.CsharpSqlite\wal_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\wal_h.cs">
<Link>Community.CsharpSqlite\wal_h.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\where_c.cs">
<Link>Community.CsharpSqlite\where_c.cs</Link>
</Compile>
<Compile Include="..\Community.CsharpSqlite\src\_Custom.cs">
<Link>Community.CsharpSqlite\_Custom.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\AssocData.cs">
<Link>TCL\src\base\AssocData.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\BackSlashResult.cs">
<Link>TCL\src\base\BackSlashResult.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\BgErrorMgr.cs">
<Link>TCL\src\base\BgErrorMgr.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\CallFrame.cs">
<Link>TCL\src\base\CallFrame.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\CharPointer.cs">
<Link>TCL\src\base\CharPointer.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\CObject.cs">
<Link>TCL\src\base\CObject.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Command.cs">
<Link>TCL\src\base\Command.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\CommandWithDispose.cs">
<Link>TCL\src\base\CommandWithDispose.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\DebugInfo.cs">
<Link>TCL\src\base\DebugInfo.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Env.cs">
<Link>TCL\src\base\Env.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\EventDeleter.cs">
<Link>TCL\src\base\EventDeleter.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\EventuallyFreed.cs">
<Link>TCL\src\base\EventuallyFreed.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Expression.cs">
<Link>TCL\src\base\Expression.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\ExprValue.cs">
<Link>TCL\src\base\ExprValue.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Extension.cs">
<Link>TCL\src\base\Extension.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\FindElemResult.cs">
<Link>TCL\src\base\FindElemResult.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\IdleHandler.cs">
<Link>TCL\src\base\IdleHandler.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\ImportedCmdData.cs">
<Link>TCL\src\base\ImportedCmdData.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\ImportRef.cs">
<Link>TCL\src\base\ImportRef.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\InternalRep.cs">
<Link>TCL\src\base\InternalRep.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Interp.cs">
<Link>TCL\src\base\Interp.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\JACL.cs">
<Link>TCL\src\base\JACL.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Notifier.cs">
<Link>TCL\src\base\Notifier.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Parser.cs">
<Link>TCL\src\base\Parser.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\ParseResult.cs">
<Link>TCL\src\base\ParseResult.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Procedure.cs">
<Link>TCL\src\base\Procedure.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\QSort.cs">
<Link>TCL\src\base\QSort.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Resolver.cs">
<Link>TCL\src\base\Resolver.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\SearchId.cs">
<Link>TCL\src\base\SearchId.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TCL.cs">
<Link>TCL\src\base\TCL.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclBoolean.cs">
<Link>TCL\src\base\TclBoolean.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclByteArray.cs">
<Link>TCL\src\base\TclByteArray.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclDouble.cs">
<Link>TCL\src\base\TclDouble.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclEvent.cs">
<Link>TCL\src\base\TclEvent.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclException.cs">
<Link>TCL\src\base\TclException.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclIndex.cs">
<Link>TCL\src\base\TclIndex.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclInteger.cs">
<Link>TCL\src\base\TclInteger.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclList.cs">
<Link>TCL\src\base\TclList.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclLong.cs">
<Link>TCL\src\base\TclLong.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclNumArgsException.cs">
<Link>TCL\src\base\TclNumArgsException.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TCLObj.cs">
<Link>TCL\src\base\TCLObj.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclObject.cs">
<Link>TCL\src\base\TclObject.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclParse.cs">
<Link>TCL\src\base\TclParse.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclPosixException.cs">
<Link>TCL\src\base\TclPosixException.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclRegexp.cs">
<Link>TCL\src\base\TclRegexp.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclRuntimeError.cs">
<Link>TCL\src\base\TclRuntimeError.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclString.cs">
<Link>TCL\src\base\TclString.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclToken.cs">
<Link>TCL\src\base\TclToken.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TclVarException.cs">
<Link>TCL\src\base\TclVarException.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TimerHandler.cs">
<Link>TCL\src\base\TimerHandler.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\TraceRecord.cs">
<Link>TCL\src\base\TraceRecord.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Util.cs">
<Link>TCL\src\base\Util.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\Var.cs">
<Link>TCL\src\base\Var.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\VarTrace.cs">
<Link>TCL\src\base\VarTrace.cs</Link>
</Compile>
<Compile Include="..\TCL\src\base\WrappedCommand.cs">
<Link>TCL\src\base\WrappedCommand.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\AfterCmd.cs">
<Link>TCL\src\commands\AfterCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\AppendCmd.cs">
<Link>TCL\src\commands\AppendCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ArrayCmd.cs">
<Link>TCL\src\commands\ArrayCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\BinaryCmd.cs">
<Link>TCL\src\commands\BinaryCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\BreakCmd.cs">
<Link>TCL\src\commands\BreakCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\CaseCmd.cs">
<Link>TCL\src\commands\CaseCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\CatchCmd.cs">
<Link>TCL\src\commands\CatchCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\CdCmd.cs">
<Link>TCL\src\commands\CdCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ClockCmd.cs">
<Link>TCL\src\commands\ClockCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\CloseCmd.cs">
<Link>TCL\src\commands\CloseCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ConcatCmd.cs">
<Link>TCL\src\commands\ConcatCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ContinueCmd.cs">
<Link>TCL\src\commands\ContinueCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\EncodingCmd.cs">
<Link>TCL\src\commands\EncodingCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\EofCmd.cs">
<Link>TCL\src\commands\EofCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ErrorCmd.cs">
<Link>TCL\src\commands\ErrorCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\EvalCmd.cs">
<Link>TCL\src\commands\EvalCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ExecCmd.cs">
<Link>TCL\src\commands\ExecCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ExitCmd.cs">
<Link>TCL\src\commands\ExitCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ExprCmd.cs">
<Link>TCL\src\commands\ExprCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\FblockedCmd.cs">
<Link>TCL\src\commands\FblockedCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\FconfigureCmd.cs">
<Link>TCL\src\commands\FconfigureCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\FileCmd.cs">
<Link>TCL\src\commands\FileCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\FlushCmd.cs">
<Link>TCL\src\commands\FlushCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ForCmd.cs">
<Link>TCL\src\commands\ForCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ForeachCmd.cs">
<Link>TCL\src\commands\ForeachCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\FormatCmd.cs">
<Link>TCL\src\commands\FormatCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\GetsCmd.cs">
<Link>TCL\src\commands\GetsCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\GlobalCmd.cs">
<Link>TCL\src\commands\GlobalCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\GlobCmd.cs">
<Link>TCL\src\commands\GlobCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\IfCmd.cs">
<Link>TCL\src\commands\IfCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\IncrCmd.cs">
<Link>TCL\src\commands\IncrCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\InfoCmd.cs">
<Link>TCL\src\commands\InfoCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\InterpAliasCmd.cs">
<Link>TCL\src\commands\InterpAliasCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\InterpCmd.cs">
<Link>TCL\src\commands\InterpCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\InterpSlaveCmd.cs">
<Link>TCL\src\commands\InterpSlaveCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\JoinCmd.cs">
<Link>TCL\src\commands\JoinCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LappendCmd.cs">
<Link>TCL\src\commands\LappendCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LindexCmd.cs">
<Link>TCL\src\commands\LindexCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LinsertCmd.cs">
<Link>TCL\src\commands\LinsertCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ListCmd.cs">
<Link>TCL\src\commands\ListCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LlengthCmd.cs">
<Link>TCL\src\commands\LlengthCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LrangeCmd.cs">
<Link>TCL\src\commands\LrangeCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LreplaceCmd.cs">
<Link>TCL\src\commands\LreplaceCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LsearchCmd.cs">
<Link>TCL\src\commands\LsearchCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LsetCmd.cs">
<Link>TCL\src\commands\LsetCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\LsortCmd.cs">
<Link>TCL\src\commands\LsortCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\NamespaceCmd.cs">
<Link>TCL\src\commands\NamespaceCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\OpenCmd.cs">
<Link>TCL\src\commands\OpenCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\PackageCmd.cs">
<Link>TCL\src\commands\PackageCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ParseAdaptor.cs">
<Link>TCL\src\commands\ParseAdaptor.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ProcCmd.cs">
<Link>TCL\src\commands\ProcCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\PutsCmd.cs">
<Link>TCL\src\commands\PutsCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\PwdCmd.cs">
<Link>TCL\src\commands\PwdCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ReadCmd.cs">
<Link>TCL\src\commands\ReadCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\RegexpCmd.cs">
<Link>TCL\src\commands\RegexpCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\RegsubCmd.cs">
<Link>TCL\src\commands\RegsubCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\RenameCmd.cs">
<Link>TCL\src\commands\RenameCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ReturnCmd.cs">
<Link>TCL\src\commands\ReturnCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\ScanCmd.cs">
<Link>TCL\src\commands\ScanCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\SeekCmd.cs">
<Link>TCL\src\commands\SeekCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\SetCmd.cs">
<Link>TCL\src\commands\SetCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\SocketChannel.cs">
<Link>TCL\src\commands\SocketChannel.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\SourceCmd.cs">
<Link>TCL\src\commands\srcCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\SplitCmd.cs">
<Link>TCL\src\commands\SplitCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\StdChannel.cs">
<Link>TCL\src\commands\StdChannel.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\StringCmd.cs">
<Link>TCL\src\commands\StringCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\StrtodResult.cs">
<Link>TCL\src\commands\StrtodResult.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\StrtoulResult.cs">
<Link>TCL\src\commands\StrtoulResult.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\SubstCmd.cs">
<Link>TCL\src\commands\SubstCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\SwitchCmd.cs">
<Link>TCL\src\commands\SwitchCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\TellCmd.cs">
<Link>TCL\src\commands\TellCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\TimeCmd.cs">
<Link>TCL\src\commands\TimeCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\TraceCmd.cs">
<Link>TCL\src\commands\TraceCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\UnsetCmd.cs">
<Link>TCL\src\commands\UnsetCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\UpdateCmd.cs">
<Link>TCL\src\commands\UpdateCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\UplevelCmd.cs">
<Link>TCL\src\commands\UplevelCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\UpvarCmd.cs">
<Link>TCL\src\commands\UpvarCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\VariableCmd.cs">
<Link>TCL\src\commands\VariableCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\VwaitCmd.cs">
<Link>TCL\src\commands\VwaitCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\commands\WhileCmd.cs">
<Link>TCL\src\commands\WhileCmd.cs</Link>
</Compile>
<Compile Include="..\TCL\src\io\Channel.cs">
<Link>TCL\src\io\Channel.cs</Link>
</Compile>
<Compile Include="..\TCL\src\io\ChannelBuffer.cs">
<Link>TCL\src\io\ChannelBuffer.cs</Link>
</Compile>
<Compile Include="..\TCL\src\io\FileChannel.cs">
<Link>TCL\src\io\FileChannel.cs</Link>
</Compile>
<Compile Include="..\TCL\src\io\FileUtil.cs">
<Link>TCL\src\io\FileUtil.cs</Link>
</Compile>
<Compile Include="..\TCL\src\io\TclInputStream.cs">
<Link>TCL\src\io\TclInputStream.cs</Link>
</Compile>
<Compile Include="..\TCL\src\io\TclIO.cs">
<Link>TCL\src\io\TclIO.cs</Link>
</Compile>
<Compile Include="..\TCL\src\io\TclOutputStream.cs">
<Link>TCL\src\io\TclOutputStream.cs</Link>
</Compile>
<Compile Include="..\TCL\src\regexp_brazil\Regexp.cs">
<Link>TCL\src\regexp_brazil\Regexp.cs</Link>
</Compile>
<Compile Include="..\TCL\src\regexp_brazil\Regsub.cs">
<Link>TCL\src\regexp_brazil\Regsub.cs</Link>
</Compile>
<Compile Include="..\TCL\src\SupportClass.cs">
<Link>TCL\src\SupportClass.cs</Link>
</Compile>
<Compile Include="..\TCL\src\tcl_h.cs">
<Link>TCL\src\tcl_h.cs</Link>
</Compile>
<Compile Include="..\TCL\src\_tcl_Conversions.cs">
<Link>TCL\src\_tcl_Conversions.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="src\tclsqlite_c.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="src\test1_c.cs" />
<Compile Include="src\test2_c.cs" />
<Compile Include="src\test3_c.cs" />
<Compile Include="src\test8_c.cs" />
<Compile Include="src\test_intarray_c.cs" />
<Compile Include="src\test9_c.cs" />
<Compile Include="src\testfixture.cs" />
<Compile Include="src\test_autoext_c.cs" />
<Compile Include="src\test_backup_c.cs" />
<Compile Include="src\test_btree_c.cs" />
<Compile Include="src\test_config_c.cs" />
<Compile Include="src\test_func_c.cs" />
<Compile Include="src\test_fuzzer_c.cs" />
<Compile Include="src\test_hexio_c.cs" />
<Compile Include="src\test_malloc_c.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="src\test_mutex_c.cs" />
<Compile Include="src\test_schema_c.cs" />
<Compile Include="src\test_stat_c.cs" />
<Compile Include="src\test_tclvar_c.cs" />
<Compile Include="src\test_vfstrace_c.cs" />
<Compile Include="src\test_vfs_c.cs" />
<Compile Include="src\test_wholenumber_c.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\test\8_3_names.test">
<Link>test\8_3_names.test</Link>
</None>
<None Include="..\test\aggerror.test">
<Link>test\aggerror.test</Link>
</None>
<None Include="..\test\alias.test">
<Link>test\alias.test</Link>
</None>
<None Include="..\test\alter.test">
<Link>test\alter.test</Link>
</None>
<None Include="..\test\alter2.test">
<Link>test\alter2.test</Link>
</None>
<None Include="..\test\alter3.test">
<Link>test\alter3.test</Link>
</None>
<None Include="..\test\alter4.test">
<Link>test\alter4.test</Link>
</None>
<None Include="..\test\analyze.test">
<Link>test\analyze.test</Link>
</None>
<None Include="..\test\analyze2.test">
<Link>test\analyze2.test</Link>
</None>
<None Include="..\test\analyze3.test">
<Link>test\analyze3.test</Link>
</None>
<None Include="..\test\analyze4.test">
<Link>test\analyze4.test</Link>
</None>
<None Include="..\test\analyze5.test">
<Link>test\analyze5.test</Link>
</None>
<None Include="..\test\analyze6.test">
<Link>test\analyze6.test</Link>
</None>
<None Include="..\test\analyze7.test">
<Link>test\analyze7.test</Link>
</None>
<None Include="..\test\async.test">
<Link>test\async.test</Link>
</None>
<None Include="..\test\async2.test">
<Link>test\async2.test</Link>
</None>
<None Include="..\test\async3.test">
<Link>test\async3.test</Link>
</None>
<None Include="..\test\async4.test">
<Link>test\async4.test</Link>
</None>
<None Include="..\test\async5.test">
<Link>test\async5.test</Link>
</None>
<None Include="..\test\attach.test">
<Link>test\attach.test</Link>
</None>
<None Include="..\test\attach2.test">
<Link>test\attach2.test</Link>
</None>
<None Include="..\test\attach3.test">
<Link>test\attach3.test</Link>
</None>
<None Include="..\test\attach4.test">
<Link>test\attach4.test</Link>
</None>
<None Include="..\test\auth.test">
<Link>test\auth.test</Link>
</None>
<None Include="..\test\auth2.test">
<Link>test\auth2.test</Link>
</None>
<None Include="..\test\auth3.test">
<Link>test\auth3.test</Link>
</None>
<None Include="..\test\autoinc.test">
<Link>test\autoinc.test</Link>
</None>
<None Include="..\test\autoindex1.test">
<Link>test\autoindex1.test</Link>
</None>
<None Include="..\test\autovacuum.test">
<Link>test\autovacuum.test</Link>
</None>
<None Include="..\test\avtrans.test">
<Link>test\avtrans.test</Link>
</None>
<None Include="..\test\backcompat.test">
<Link>test\backcompat.test</Link>
</None>
<None Include="..\test\backup.test">
<Link>test\backup.test</Link>
</None>
<None Include="..\test\backup2.test">
<Link>test\backup2.test</Link>
</None>
<None Include="..\test\badutf.test">
<Link>test\badutf.test</Link>
</None>
<None Include="..\test\badutf2.test">
<Link>test\badutf2.test</Link>
</None>
<None Include="..\test\between.test">
<Link>test\between.test</Link>
</None>
<None Include="..\test\bigfile.test">
<Link>test\bigfile.test</Link>
</None>
<None Include="..\test\bigrow.test">
<Link>test\bigrow.test</Link>
</None>
<None Include="..\test\bind.test">
<Link>test\bind.test</Link>
</None>
<None Include="..\test\bindxfer.test">
<Link>test\bindxfer.test</Link>
</None>
<None Include="..\test\bitvec.test">
<Link>test\bitvec.test</Link>
</None>
<None Include="..\test\blob.test">
<Link>test\blob.test</Link>
</None>
<None Include="..\test\boundary1.tcl">
<Link>test\boundary1.tcl</Link>
</None>
<None Include="..\test\boundary1.test">
<Link>test\boundary1.test</Link>
</None>
<None Include="..\test\boundary2.tcl">
<Link>test\boundary2.tcl</Link>
</None>
<None Include="..\test\boundary2.test">
<Link>test\boundary2.test</Link>
</None>
<None Include="..\test\boundary3.tcl">
<Link>test\boundary3.tcl</Link>
</None>
<None Include="..\test\boundary3.test">
<Link>test\boundary3.test</Link>
</None>
<None Include="..\test\boundary4.tcl">
<Link>test\boundary4.tcl</Link>
</None>
<None Include="..\test\boundary4.test">
<Link>test\boundary4.test</Link>
</None>
<None Include="..\test\busy.test">
<Link>test\busy.test</Link>
</None>
<None Include="..\test\cache.test">
<Link>test\cache.test</Link>
</None>
<None Include="..\test\capi2.test">
<Link>test\capi2.test</Link>
</None>
<None Include="..\test\capi3.test">
<Link>test\capi3.test</Link>
</None>
<None Include="..\test\capi3b.test">
<Link>test\capi3b.test</Link>
</None>
<None Include="..\test\capi3c.test">
<Link>test\capi3c.test</Link>
</None>
<None Include="..\test\capi3d.test">
<Link>test\capi3d.test</Link>
</None>
<None Include="..\test\capi3e.test">
<Link>test\capi3e.test</Link>
</None>
<None Include="..\test\cast.test">
<Link>test\cast.test</Link>
</None>
<None Include="..\test\check.test">
<Link>test\check.test</Link>
</None>
<None Include="..\test\coalesce.test">
<Link>test\coalesce.test</Link>
</None>
<None Include="..\test\collate1.test">
<Link>test\collate1.test</Link>
</None>
<None Include="..\test\collate2.test">
<Link>test\collate2.test</Link>
</None>
<None Include="..\test\collate3.test">
<Link>test\collate3.test</Link>
</None>
<None Include="..\test\collate4.test">
<Link>test\collate4.test</Link>
</None>
<None Include="..\test\collate5.test">
<Link>test\collate5.test</Link>
</None>
<None Include="..\test\collate6.test">
<Link>test\collate6.test</Link>
</None>
<None Include="..\test\collate7.test">
<Link>test\collate7.test</Link>
</None>
<None Include="..\test\collate8.test">
<Link>test\collate8.test</Link>
</None>
<None Include="..\test\collate9.test">
<Link>test\collate9.test</Link>
</None>
<None Include="..\test\collateA.test">
<Link>test\collateA.test</Link>
</None>
<None Include="..\test\colmeta.test">
<Link>test\colmeta.test</Link>
</None>
<None Include="..\test\colname.test">
<Link>test\colname.test</Link>
</None>
<None Include="..\test\conflict.test">
<Link>test\conflict.test</Link>
</None>
<None Include="..\test\corrupt.test">
<Link>test\corrupt.test</Link>
</None>
<None Include="..\test\corrupt2.test">
<Link>test\corrupt2.test</Link>
</None>
<None Include="..\test\corrupt3.test">
<Link>test\corrupt3.test</Link>
</None>
<None Include="..\test\corrupt4.test">
<Link>test\corrupt4.test</Link>
</None>
<None Include="..\test\corrupt5.test">
<Link>test\corrupt5.test</Link>
</None>
<None Include="..\test\corrupt6.test">
<Link>test\corrupt6.test</Link>
</None>
<None Include="..\test\corrupt7.test">
<Link>test\corrupt7.test</Link>
</None>
<None Include="..\test\corrupt8.test">
<Link>test\corrupt8.test</Link>
</None>
<None Include="..\test\corrupt9.test">
<Link>test\corrupt9.test</Link>
</None>
<None Include="..\test\corruptA.test">
<Link>test\corruptA.test</Link>
</None>
<None Include="..\test\corruptB.test">
<Link>test\corruptB.test</Link>
</None>
<None Include="..\test\corruptC.test">
<Link>test\corruptC.test</Link>
</None>
<None Include="..\test\corruptD.test">
<Link>test\corruptD.test</Link>
</None>
<None Include="..\test\corruptE.test">
<Link>test\corruptE.test</Link>
</None>
<None Include="..\test\count.test">
<Link>test\count.test</Link>
</None>
<None Include="..\test\crash.test">
<Link>test\crash.test</Link>
</None>
<None Include="..\test\crash2.test">
<Link>test\crash2.test</Link>
</None>
<None Include="..\test\crash3.test">
<Link>test\crash3.test</Link>
</None>
<None Include="..\test\crash4.test">
<Link>test\crash4.test</Link>
</None>
<None Include="..\test\crash5.test">
<Link>test\crash5.test</Link>
</None>
<None Include="..\test\crash6.test">
<Link>test\crash6.test</Link>
</None>
<None Include="..\test\crash7.test">
<Link>test\crash7.test</Link>
</None>
<None Include="..\test\crash8.test">
<Link>test\crash8.test</Link>
</None>
<None Include="..\test\createtab.test">
<Link>test\createtab.test</Link>
</None>
<None Include="..\test\cse.test">
<Link>test\cse.test</Link>
</None>
<None Include="..\test\ctime.test">
<Link>test\ctime.test</Link>
</None>
<None Include="..\test\date.test">
<Link>test\date.test</Link>
</None>
<None Include="..\test\default.test">
<Link>test\default.test</Link>
</None>
<None Include="..\test\delete.test">
<Link>test\delete.test</Link>
</None>
<None Include="..\test\delete2.test">
<Link>test\delete2.test</Link>
</None>
<None Include="..\test\delete3.test">
<Link>test\delete3.test</Link>
</None>
<None Include="..\test\descidx1.test">
<Link>test\descidx1.test</Link>
</None>
<None Include="..\test\descidx2.test">
<Link>test\descidx2.test</Link>
</None>
<None Include="..\test\descidx3.test">
<Link>test\descidx3.test</Link>
</None>
<None Include="..\test\diskfull.test">
<Link>test\diskfull.test</Link>
</None>
<None Include="..\test\distinctagg.test">
<Link>test\distinctagg.test</Link>
</None>
<None Include="..\test\enc.test">
<Link>test\enc.test</Link>
</None>
<None Include="..\test\enc2.test">
<Link>test\enc2.test</Link>
</None>
<None Include="..\test\enc3.test">
<Link>test\enc3.test</Link>
</None>
<None Include="..\test\enc4.test">
<Link>test\enc4.test</Link>
</None>
<None Include="..\test\eqp.test">
<Link>test\eqp.test</Link>
</None>
<None Include="..\test\eval.test">
<Link>test\eval.test</Link>
</None>
<None Include="..\test\exclusive.test">
<Link>test\exclusive.test</Link>
</None>
<None Include="..\test\exclusive2.test">
<Link>test\exclusive2.test</Link>
</None>
<None Include="..\test\exec.test">
<Link>test\exec.test</Link>
</None>
<None Include="..\test\exists.test">
<Link>test\exists.test</Link>
</None>
<None Include="..\test\expr.test">
<Link>test\expr.test</Link>
</None>
<None Include="..\test\e_createtable.test">
<Link>test\e_createtable.test</Link>
</None>
<None Include="..\test\e_delete.test">
<Link>test\e_delete.test</Link>
</None>
<None Include="..\test\e_droptrigger.test">
<Link>test\e_droptrigger.test</Link>
</None>
<None Include="..\test\e_dropview.test">
<Link>test\e_dropview.test</Link>
</None>
<None Include="..\test\e_expr.test">
<Link>test\e_expr.test</Link>
</None>
<None Include="..\test\e_fkey.test">
<Link>test\e_fkey.test</Link>
</None>
<None Include="..\test\e_insert.test">
<Link>test\e_insert.test</Link>
</None>
<None Include="..\test\e_reindex.test">
<Link>test\e_reindex.test</Link>
</None>
<None Include="..\test\e_resolve.test">
<Link>test\e_resolve.test</Link>
</None>
<None Include="..\test\e_select.test">
<Link>test\e_select.test</Link>
</None>
<None Include="..\test\e_select2.test">
<Link>test\e_select2.test</Link>
</None>
<None Include="..\test\e_update.test">
<Link>test\e_update.test</Link>
</None>
<None Include="..\test\e_uri.test">
<Link>test\e_uri.test</Link>
</None>
<None Include="..\test\e_vacuum.test">
<Link>test\e_vacuum.test</Link>
</None>
<None Include="..\test\filectrl.test">
<Link>test\filectrl.test</Link>
</None>
<None Include="..\test\filefmt.test">
<Link>test\filefmt.test</Link>
</None>
<None Include="..\test\fkey1.test">
<Link>test\fkey1.test</Link>
</None>
<None Include="..\test\fkey2.test">
<Link>test\fkey2.test</Link>
</None>
<None Include="..\test\fkey3.test">
<Link>test\fkey3.test</Link>
</None>
<None Include="..\test\fkey4.test">
<Link>test\fkey4.test</Link>
</None>
<None Include="..\test\format4.test">
<Link>test\format4.test</Link>
</None>
<None Include="..\test\func.test">
<Link>test\func.test</Link>
</None>
<None Include="..\test\func2.test">
<Link>test\func2.test</Link>
</None>
<None Include="..\test\func3.test">
<Link>test\func3.test</Link>
</None>
<None Include="..\test\fuzz.test">
<Link>test\fuzz.test</Link>
</None>
<None Include="..\test\fuzz2.test">
<Link>test\fuzz2.test</Link>
</None>
<None Include="..\test\fuzz3.test">
<Link>test\fuzz3.test</Link>
</None>
<None Include="..\test\fuzzer1.test">
<Link>test\fuzzer1.test</Link>
</None>
<None Include="..\test\fuzz_common.tcl">
<Link>test\fuzz_common.tcl</Link>
</None>
<None Include="..\test\hook.test">
<Link>test\hook.test</Link>
</None>
<None Include="..\test\icu.test">
<Link>test\icu.test</Link>
</None>
<None Include="..\test\in.test">
<Link>test\in.test</Link>
</None>
<None Include="..\test\in2.test">
<Link>test\in2.test</Link>
</None>
<None Include="..\test\in3.test">
<Link>test\in3.test</Link>
</None>
<None Include="..\test\in4.test">
<Link>test\in4.test</Link>
</None>
<None Include="..\test\incrblob.test">
<Link>test\incrblob.test</Link>
</None>
<None Include="..\test\incrblob2.test">
<Link>test\incrblob2.test</Link>
</None>
<None Include="..\test\incrblob3.test">
<Link>test\incrblob3.test</Link>
</None>
<None Include="..\test\incrvacuum.test">
<Link>test\incrvacuum.test</Link>
</None>
<None Include="..\test\incrvacuum2.test">
<Link>test\incrvacuum2.test</Link>
</None>
<None Include="..\test\index.test">
<Link>test\index.test</Link>
</None>
<None Include="..\test\index2.test">
<Link>test\index2.test</Link>
</None>
<None Include="..\test\index3.test">
<Link>test\index3.test</Link>
</None>
<None Include="..\test\indexedby.test">
<Link>test\indexedby.test</Link>
</None>
<None Include="..\test\init.test">
<Link>test\init.test</Link>
</None>
<None Include="..\test\insert.test">
<Link>test\insert.test</Link>
</None>
<None Include="..\test\insert2.test">
<Link>test\insert2.test</Link>
</None>
<None Include="..\test\insert3.test">
<Link>test\insert3.test</Link>
</None>
<None Include="..\test\insert4.test">
<Link>test\insert4.test</Link>
</None>
<None Include="..\test\insert5.test">
<Link>test\insert5.test</Link>
</None>
<None Include="..\test\intarray.test">
<Link>test\intarray.test</Link>
</None>
<None Include="..\test\interrupt.test">
<Link>test\interrupt.test</Link>
</None>
<None Include="..\test\intpkey.test">
<Link>test\intpkey.test</Link>
</None>
<None Include="..\test\join.test">
<Link>test\join.test</Link>
</None>
<None Include="..\test\join2.test">
<Link>test\join2.test</Link>
</None>
<None Include="..\test\join3.test">
<Link>test\join3.test</Link>
</None>
<None Include="..\test\join4.test">
<Link>test\join4.test</Link>
</None>
<None Include="..\test\join5.test">
<Link>test\join5.test</Link>
</None>
<None Include="..\test\join6.test">
<Link>test\join6.test</Link>
</None>
<None Include="..\test\journal1.test">
<Link>test\journal1.test</Link>
</None>
<None Include="..\test\journal2.test">
<Link>test\journal2.test</Link>
</None>
<None Include="..\test\journal3.test">
<Link>test\journal3.test</Link>
</None>
<None Include="..\test\jrnlmode.test">
<Link>test\jrnlmode.test</Link>
</None>
<None Include="..\test\jrnlmode2.test">
<Link>test\jrnlmode2.test</Link>
</None>
<None Include="..\test\jrnlmode3.test">
<Link>test\jrnlmode3.test</Link>
</None>
<None Include="..\test\keyword1.test">
<Link>test\keyword1.test</Link>
</None>
<None Include="..\test\lastinsert.test">
<Link>test\lastinsert.test</Link>
</None>
<None Include="..\test\laststmtchanges.test">
<Link>test\laststmtchanges.test</Link>
</None>
<None Include="..\test\like.test">
<Link>test\like.test</Link>
</None>
<None Include="..\test\like2.test">
<Link>test\like2.test</Link>
</None>
<None Include="..\test\limit.test">
<Link>test\limit.test</Link>
</None>
<None Include="..\test\loadext.test">
<Link>test\loadext.test</Link>
</None>
<None Include="..\test\loadext2.test">
<Link>test\loadext2.test</Link>
</None>
<None Include="..\test\lock.test">
<Link>test\lock.test</Link>
</None>
<None Include="..\test\lock5.test">
<Link>test\lock5.test</Link>
</None>
<None Include="..\test\lock6.test">
<Link>test\lock6.test</Link>
</None>
<None Include="..\test\lock7.test">
<Link>test\lock7.test</Link>
</None>
<None Include="..\test\lock_common.tcl">
<Link>test\lock_common.tcl</Link>
</None>
<None Include="..\test\lookaside.test">
<Link>test\lookaside.test</Link>
</None>
<None Include="..\test\main.test">
<Link>test\main.test</Link>
</None>
<None Include="..\test\make-where7.tcl">
<Link>test\make-where7.tcl</Link>
</None>
<None Include="..\test\malloc_common.tcl">
<Link>test\malloc_common.tcl</Link>
</None>
<None Include="..\test\manydb.test">
<Link>test\manydb.test</Link>
</None>
<None Include="..\test\mem5.test">
<Link>test\mem5.test</Link>
</None>
<None Include="..\test\memdb.test">
<Link>test\memdb.test</Link>
</None>
<None Include="..\test\memleak.test">
<Link>test\memleak.test</Link>
</None>
<None Include="..\test\memsubsys1.test">
<Link>test\memsubsys1.test</Link>
</None>
<None Include="..\test\minmax.test">
<Link>test\minmax.test</Link>
</None>
<None Include="..\test\minmax2.test">
<Link>test\minmax2.test</Link>
</None>
<None Include="..\test\minmax3.test">
<Link>test\minmax3.test</Link>
</None>
<None Include="..\test\misc1.test">
<Link>test\misc1.test</Link>
</None>
<None Include="..\test\misc2.test">
<Link>test\misc2.test</Link>
</None>
<None Include="..\test\misc3.test">
<Link>test\misc3.test</Link>
</None>
<None Include="..\test\misc4.test">
<Link>test\misc4.test</Link>
</None>
<None Include="..\test\misc5.test">
<Link>test\misc5.test</Link>
</None>
<None Include="..\test\misc6.test">
<Link>test\misc6.test</Link>
</None>
<None Include="..\test\misc7.test">
<Link>test\misc7.test</Link>
</None>
<None Include="..\test\misuse.test">
<Link>test\misuse.test</Link>
</None>
<None Include="..\test\mutex1.test">
<Link>test\mutex1.test</Link>
</None>
<None Include="..\test\mutex2.test">
<Link>test\mutex2.test</Link>
</None>
<None Include="..\test\nan.test">
<Link>test\nan.test</Link>
</None>
<None Include="..\test\notify1.test">
<Link>test\notify1.test</Link>
</None>
<None Include="..\test\notify2.test">
<Link>test\notify2.test</Link>
</None>
<None Include="..\test\notify3.test">
<Link>test\notify3.test</Link>
</None>
<None Include="..\test\notnull.test">
<Link>test\notnull.test</Link>
</None>
<None Include="..\test\null.test">
<Link>test\null.test</Link>
</None>
<None Include="..\test\openv2.test">
<Link>test\openv2.test</Link>
</None>
<None Include="..\test\pager1.test">
<Link>test\pager1.test</Link>
</None>
<None Include="..\test\pager2.test">
<Link>test\pager2.test</Link>
</None>
<None Include="..\test\pager3.test">
<Link>test\pager3.test</Link>
</None>
<None Include="..\test\pageropt.test">
<Link>test\pageropt.test</Link>
</None>
<None Include="..\test\pagesize.test">
<Link>test\pagesize.test</Link>
</None>
<None Include="..\test\pcache.test">
<Link>test\pcache.test</Link>
</None>
<None Include="..\test\pcache2.test">
<Link>test\pcache2.test</Link>
</None>
<None Include="..\test\permutations.test">
<Link>test\permutations.test</Link>
</None>
<None Include="..\test\pragma.test">
<Link>test\pragma.test</Link>
</None>
<None Include="..\test\pragma2.test">
<Link>test\pragma2.test</Link>
</None>
<None Include="..\test\printf.test">
<Link>test\printf.test</Link>
</None>
<None Include="..\test\progress.test">
<Link>test\progress.test</Link>
</None>
<None Include="..\test\ptrchng.test">
<Link>test\ptrchng.test</Link>
</None>
<None Include="..\test\quota.test">
<Link>test\quota.test</Link>
</None>
<None Include="..\test\quote.test">
<Link>test\quote.test</Link>
</None>
<None Include="..\test\randexpr1.tcl">
<Link>test\randexpr1.tcl</Link>
</None>
<None Include="..\test\randexpr1.test">
<Link>test\randexpr1.test</Link>
</None>
<None Include="..\test\rdonly.test">
<Link>test\rdonly.test</Link>
</None>
<None Include="..\test\reindex.test">
<Link>test\reindex.test</Link>
</None>
<None Include="..\test\rollback.test">
<Link>test\rollback.test</Link>
</None>
<None Include="..\test\rowhash.test">
<Link>test\rowhash.test</Link>
</None>
<None Include="..\test\rowid.test">
<Link>test\rowid.test</Link>
</None>
<None Include="..\test\savepoint.test">
<Link>test\savepoint.test</Link>
</None>
<None Include="..\test\savepoint2.test">
<Link>test\savepoint2.test</Link>
</None>
<None Include="..\test\savepoint3.test">
<Link>test\savepoint3.test</Link>
</None>
<None Include="..\test\savepoint4.test">
<Link>test\savepoint4.test</Link>
</None>
<None Include="..\test\savepoint5.test">
<Link>test\savepoint5.test</Link>
</None>
<None Include="..\test\savepoint6.test">
<Link>test\savepoint6.test</Link>
</None>
<None Include="..\test\schema.test">
<Link>test\schema.test</Link>
</None>
<None Include="..\test\schema2.test">
<Link>test\schema2.test</Link>
</None>
<None Include="..\test\schema3.test">
<Link>test\schema3.test</Link>
</None>
<None Include="..\test\schema4.test">
<Link>test\schema4.test</Link>
</None>
<None Include="..\test\securedel.test">
<Link>test\securedel.test</Link>
</None>
<None Include="..\test\select1.test">
<Link>test\select1.test</Link>
</None>
<None Include="..\test\select2.test">
<Link>test\select2.test</Link>
</None>
<None Include="..\test\select3.test">
<Link>test\select3.test</Link>
</None>
<None Include="..\test\select4.test">
<Link>test\select4.test</Link>
</None>
<None Include="..\test\select5.test">
<Link>test\select5.test</Link>
</None>
<None Include="..\test\select6.test">
<Link>test\select6.test</Link>
</None>
<None Include="..\test\select7.test">
<Link>test\select7.test</Link>
</None>
<None Include="..\test\select8.test">
<Link>test\select8.test</Link>
</None>
<None Include="..\test\select9.test">
<Link>test\select9.test</Link>
</None>
<None Include="..\test\selectA.test">
<Link>test\selectA.test</Link>
</None>
<None Include="..\test\selectB.test">
<Link>test\selectB.test</Link>
</None>
<None Include="..\test\selectC.test">
<Link>test\selectC.test</Link>
</None>
<None Include="..\test\server1.test">
<Link>test\server1.test</Link>
</None>
<None Include="..\test\shared.test">
<Link>test\shared.test</Link>
</None>
<None Include="..\test\shared2.test">
<Link>test\shared2.test</Link>
</None>
<None Include="..\test\shared3.test">
<Link>test\shared3.test</Link>
</None>
<None Include="..\test\shared4.test">
<Link>test\shared4.test</Link>
</None>
<None Include="..\test\shared6.test">
<Link>test\shared6.test</Link>
</None>
<None Include="..\test\shared7.test">
<Link>test\shared7.test</Link>
</None>
<None Include="..\test\sharedlock.test">
<Link>test\sharedlock.test</Link>
</None>
<None Include="..\test\shared_err.test">
<Link>test\shared_err.test</Link>
</None>
<None Include="..\test\shortread1.test">
<Link>test\shortread1.test</Link>
</None>
<None Include="..\test\sidedelete.test">
<Link>test\sidedelete.test</Link>
</None>
<None Include="..\test\soak.test">
<Link>test\soak.test</Link>
</None>
<None Include="..\test\softheap1.test">
<Link>test\softheap1.test</Link>
</None>
<None Include="..\test\sort.test">
<Link>test\sort.test</Link>
</None>
<None Include="..\test\speed1.test">
<Link>test\speed1.test</Link>
</None>
<None Include="..\test\speed1p.explain">
<Link>test\speed1p.explain</Link>
</None>
<None Include="..\test\speed1p.test">
<Link>test\speed1p.test</Link>
</None>
<None Include="..\test\speed2.test">
<Link>test\speed2.test</Link>
</None>
<None Include="..\test\speed3.test">
<Link>test\speed3.test</Link>
</None>
<None Include="..\test\speed4.test">
<Link>test\speed4.test</Link>
</None>
<None Include="..\test\speed4p.explain">
<Link>test\speed4p.explain</Link>
</None>
<None Include="..\test\speed4p.test">
<Link>test\speed4p.test</Link>
</None>
<None Include="..\test\sqllimits1.test">
<Link>test\sqllimits1.test</Link>
</None>
<None Include="..\test\stat.test">
<Link>test\stat.test</Link>
</None>
<None Include="..\test\stmt.test">
<Link>test\stmt.test</Link>
</None>
<None Include="..\test\subquery.test">
<Link>test\subquery.test</Link>
</None>
<None Include="..\test\subselect.test">
<Link>test\subselect.test</Link>
</None>
<None Include="..\test\substr.test">
<Link>test\substr.test</Link>
</None>
<None Include="..\test\sync.test">
<Link>test\sync.test</Link>
</None>
<None Include="..\test\table.test">
<Link>test\table.test</Link>
</None>
<None Include="..\test\tableapi.test">
<Link>test\tableapi.test</Link>
</None>
<None Include="..\test\tempdb.test">
<Link>test\tempdb.test</Link>
</None>
<None Include="..\test\temptable.test">
<Link>test\temptable.test</Link>
</None>
<None Include="..\test\temptrigger.test">
<Link>test\temptrigger.test</Link>
</None>
<None Include="..\test\tester.tcl">
<Link>test\tester.tcl</Link>
</None>
<None Include="..\test\thread_common.tcl">
<Link>test\thread_common.tcl</Link>
</None>
<None Include="..\test\tkt-02a8e81d44.test">
<Link>test\tkt-02a8e81d44.test</Link>
</None>
<None Include="..\test\tkt-26ff0c2d1e.test">
<Link>test\tkt-26ff0c2d1e.test</Link>
</None>
<None Include="..\test\tkt-2d1a5c67d.test">
<Link>test\tkt-2d1a5c67d.test</Link>
</None>
<None Include="..\test\tkt-2ea2425d34.test">
<Link>test\tkt-2ea2425d34.test</Link>
</None>
<None Include="..\test\tkt-31338dca7e.test">
<Link>test\tkt-31338dca7e.test</Link>
</None>
<None Include="..\test\tkt-313723c356.test">
<Link>test\tkt-313723c356.test</Link>
</None>
<None Include="..\test\tkt-38cb5df375.test">
<Link>test\tkt-38cb5df375.test</Link>
</None>
<None Include="..\test\tkt-3998683a16.test">
<Link>test\tkt-3998683a16.test</Link>
</None>
<None Include="..\test\tkt-3fe897352e.test">
<Link>test\tkt-3fe897352e.test</Link>
</None>
<None Include="..\test\tkt-4a03edc4c8.test">
<Link>test\tkt-4a03edc4c8.test</Link>
</None>
<None Include="..\test\tkt-5d863f876e.test">
<Link>test\tkt-5d863f876e.test</Link>
</None>
<None Include="..\test\tkt-5e10420e8d.test">
<Link>test\tkt-5e10420e8d.test</Link>
</None>
<None Include="..\test\tkt-5ee23731f.test">
<Link>test\tkt-5ee23731f.test</Link>
</None>
<None Include="..\test\tkt-752e1646fc.test">
<Link>test\tkt-752e1646fc.test</Link>
</None>
<None Include="..\test\tkt-78e04e52ea.test">
<Link>test\tkt-78e04e52ea.test</Link>
</None>
<None Include="..\test\tkt-80ba201079.test">
<Link>test\tkt-80ba201079.test</Link>
</None>
<None Include="..\test\tkt-80e031a00f.test">
<Link>test\tkt-80e031a00f.test</Link>
</None>
<None Include="..\test\tkt-8454a207b9.test">
<Link>test\tkt-8454a207b9.test</Link>
</None>
<None Include="..\test\tkt-94c04eaadb.test">
<Link>test\tkt-94c04eaadb.test</Link>
</None>
<None Include="..\test\tkt-9d68c883.test">
<Link>test\tkt-9d68c883.test</Link>
</None>
<None Include="..\test\tkt-b351d95f9.test">
<Link>test\tkt-b351d95f9.test</Link>
</None>
<None Include="..\test\tkt-b72787b1.test">
<Link>test\tkt-b72787b1.test</Link>
</None>
<None Include="..\test\tkt-cbd054fa6b.test">
<Link>test\tkt-cbd054fa6b.test</Link>
</None>
<None Include="..\test\tkt-d11f09d36e.test">
<Link>test\tkt-d11f09d36e.test</Link>
</None>
<None Include="..\test\tkt-d82e3f3721.test">
<Link>test\tkt-d82e3f3721.test</Link>
</None>
<None Include="..\test\tkt-f3e5abed55.test">
<Link>test\tkt-f3e5abed55.test</Link>
</None>
<None Include="..\test\tkt-f777251dc7a.test">
<Link>test\tkt-f777251dc7a.test</Link>
</None>
<None Include="..\test\tkt-f7b4edec.test">
<Link>test\tkt-f7b4edec.test</Link>
</None>
<None Include="..\test\tkt-f973c7ac31.test">
<Link>test\tkt-f973c7ac31.test</Link>
</None>
<None Include="..\test\tkt-fc62af4523.test">
<Link>test\tkt-fc62af4523.test</Link>
</None>
<None Include="..\test\tkt1435.test">
<Link>test\tkt1435.test</Link>
</None>
<None Include="..\test\tkt1443.test">
<Link>test\tkt1443.test</Link>
</None>
<None Include="..\test\tkt1444.test">
<Link>test\tkt1444.test</Link>
</None>
<None Include="..\test\tkt1449.test">
<Link>test\tkt1449.test</Link>
</None>
<None Include="..\test\tkt1473.test">
<Link>test\tkt1473.test</Link>
</None>
<None Include="..\test\tkt1501.test">
<Link>test\tkt1501.test</Link>
</None>
<None Include="..\test\tkt1512.test">
<Link>test\tkt1512.test</Link>
</None>
<None Include="..\test\tkt1514.test">
<Link>test\tkt1514.test</Link>
</None>
<None Include="..\test\tkt1536.test">
<Link>test\tkt1536.test</Link>
</None>
<None Include="..\test\tkt1537.test">
<Link>test\tkt1537.test</Link>
</None>
<None Include="..\test\tkt1567.test">
<Link>test\tkt1567.test</Link>
</None>
<None Include="..\test\tkt1644.test">
<Link>test\tkt1644.test</Link>
</None>
<None Include="..\test\tkt1667.test">
<Link>test\tkt1667.test</Link>
</None>
<None Include="..\test\tkt1873.test">
<Link>test\tkt1873.test</Link>
</None>
<None Include="..\test\tkt2141.test">
<Link>test\tkt2141.test</Link>
</None>
<None Include="..\test\tkt2192.test">
<Link>test\tkt2192.test</Link>
</None>
<None Include="..\test\tkt2213.test">
<Link>test\tkt2213.test</Link>
</None>
<None Include="..\test\tkt2251.test">
<Link>test\tkt2251.test</Link>
</None>
<None Include="..\test\tkt2285.test">
<Link>test\tkt2285.test</Link>
</None>
<None Include="..\test\tkt2332.test">
<Link>test\tkt2332.test</Link>
</None>
<None Include="..\test\tkt2339.test">
<Link>test\tkt2339.test</Link>
</None>
<None Include="..\test\tkt2391.test">
<Link>test\tkt2391.test</Link>
</None>
<None Include="..\test\tkt2409.test">
<Link>test\tkt2409.test</Link>
</None>
<None Include="..\test\tkt2450.test">
<Link>test\tkt2450.test</Link>
</None>
<None Include="..\test\tkt2565.test">
<Link>test\tkt2565.test</Link>
</None>
<None Include="..\test\tkt2640.test">
<Link>test\tkt2640.test</Link>
</None>
<None Include="..\test\tkt2643.test">
<Link>test\tkt2643.test</Link>
</None>
<None Include="..\test\tkt2686.test">
<Link>test\tkt2686.test</Link>
</None>
<None Include="..\test\tkt2767.test">
<Link>test\tkt2767.test</Link>
</None>
<None Include="..\test\tkt2817.test">
<Link>test\tkt2817.test</Link>
</None>
<None Include="..\test\tkt2820.test">
<Link>test\tkt2820.test</Link>
</None>
<None Include="..\test\tkt2822.test">
<Link>test\tkt2822.test</Link>
</None>
<None Include="..\test\tkt2832.test">
<Link>test\tkt2832.test</Link>
</None>
<None Include="..\test\tkt2854.test">
<Link>test\tkt2854.test</Link>
</None>
<None Include="..\test\tkt2920.test">
<Link>test\tkt2920.test</Link>
</None>
<None Include="..\test\tkt2927.test">
<Link>test\tkt2927.test</Link>
</None>
<None Include="..\test\tkt2942.test">
<Link>test\tkt2942.test</Link>
</None>
<None Include="..\test\tkt3080.test">
<Link>test\tkt3080.test</Link>
</None>
<None Include="..\test\tkt3093.test">
<Link>test\tkt3093.test</Link>
</None>
<None Include="..\test\tkt3121.test">
<Link>test\tkt3121.test</Link>
</None>
<None Include="..\test\tkt3201.test">
<Link>test\tkt3201.test</Link>
</None>
<None Include="..\test\tkt3292.test">
<Link>test\tkt3292.test</Link>
</None>
<None Include="..\test\tkt3298.test">
<Link>test\tkt3298.test</Link>
</None>
<None Include="..\test\tkt3334.test">
<Link>test\tkt3334.test</Link>
</None>
<None Include="..\test\tkt3346.test">
<Link>test\tkt3346.test</Link>
</None>
<None Include="..\test\tkt3357.test">
<Link>test\tkt3357.test</Link>
</None>
<None Include="..\test\tkt3419.test">
<Link>test\tkt3419.test</Link>
</None>
<None Include="..\test\tkt3424.test">
<Link>test\tkt3424.test</Link>
</None>
<None Include="..\test\tkt3442.test">
<Link>test\tkt3442.test</Link>
</None>
<None Include="..\test\tkt3457.test">
<Link>test\tkt3457.test</Link>
</None>
<None Include="..\test\tkt3461.test">
<Link>test\tkt3461.test</Link>
</None>
<None Include="..\test\tkt3493.test">
<Link>test\tkt3493.test</Link>
</None>
<None Include="..\test\tkt3508.test">
<Link>test\tkt3508.test</Link>
</None>
<None Include="..\test\tkt3522.test">
<Link>test\tkt3522.test</Link>
</None>
<None Include="..\test\tkt3527.test">
<Link>test\tkt3527.test</Link>
</None>
<None Include="..\test\tkt3541.test">
<Link>test\tkt3541.test</Link>
</None>
<None Include="..\test\tkt3554.test">
<Link>test\tkt3554.test</Link>
</None>
<None Include="..\test\tkt3581.test">
<Link>test\tkt3581.test</Link>
</None>
<None Include="..\test\tkt35xx.test">
<Link>test\tkt35xx.test</Link>
</None>
<None Include="..\test\tkt3630.test">
<Link>test\tkt3630.test</Link>
</None>
<None Include="..\test\tkt3718.test">
<Link>test\tkt3718.test</Link>
</None>
<None Include="..\test\tkt3731.test">
<Link>test\tkt3731.test</Link>
</None>
<None Include="..\test\tkt3757.test">
<Link>test\tkt3757.test</Link>
</None>
<None Include="..\test\tkt3761.test">
<Link>test\tkt3761.test</Link>
</None>
<None Include="..\test\tkt3762.test">
<Link>test\tkt3762.test</Link>
</None>
<None Include="..\test\tkt3773.test">
<Link>test\tkt3773.test</Link>
</None>
<None Include="..\test\tkt3791.test">
<Link>test\tkt3791.test</Link>
</None>
<None Include="..\test\tkt3793.test">
<Link>test\tkt3793.test</Link>
</None>
<None Include="..\test\tkt3810.test">
<Link>test\tkt3810.test</Link>
</None>
<None Include="..\test\tkt3824.test">
<Link>test\tkt3824.test</Link>
</None>
<None Include="..\test\tkt3832.test">
<Link>test\tkt3832.test</Link>
</None>
<None Include="..\test\tkt3838.test">
<Link>test\tkt3838.test</Link>
</None>
<None Include="..\test\tkt3841.test">
<Link>test\tkt3841.test</Link>
</None>
<None Include="..\test\tkt3871.test">
<Link>test\tkt3871.test</Link>
</None>
<None Include="..\test\tkt3879.test">
<Link>test\tkt3879.test</Link>
</None>
<None Include="..\test\tkt3911.test">
<Link>test\tkt3911.test</Link>
</None>
<None Include="..\test\tkt3918.test">
<Link>test\tkt3918.test</Link>
</None>
<None Include="..\test\tkt3922.test">
<Link>test\tkt3922.test</Link>
</None>
<None Include="..\test\tkt3929.test">
<Link>test\tkt3929.test</Link>
</None>
<None Include="..\test\tkt3935.test">
<Link>test\tkt3935.test</Link>
</None>
<None Include="..\test\tkt3992.test">
<Link>test\tkt3992.test</Link>
</None>
<None Include="..\test\tkt3997.test">
<Link>test\tkt3997.test</Link>
</None>
<None Include="..\test\tkt4018.test">
<Link>test\tkt4018.test</Link>
</None>
<None Include="..\test\tokenize.test">
<Link>test\tokenize.test</Link>
</None>
<None Include="..\test\trace.test">
<Link>test\trace.test</Link>
</None>
<None Include="..\test\trace2.test">
<Link>test\trace2.test</Link>
</None>
<None Include="..\test\trans.test">
<Link>test\trans.test</Link>
</None>
<None Include="..\test\trans2.test">
<Link>test\trans2.test</Link>
</None>
<None Include="..\test\trans3.test">
<Link>test\trans3.test</Link>
</None>
<None Include="..\test\trigger1.test">
<Link>test\trigger1.test</Link>
</None>
<None Include="..\test\trigger2.test">
<Link>test\trigger2.test</Link>
</None>
<None Include="..\test\trigger3.test">
<Link>test\trigger3.test</Link>
</None>
<None Include="..\test\trigger4.test">
<Link>test\trigger4.test</Link>
</None>
<None Include="..\test\trigger5.test">
<Link>test\trigger5.test</Link>
</None>
<None Include="..\test\trigger6.test">
<Link>test\trigger6.test</Link>
</None>
<None Include="..\test\trigger7.test">
<Link>test\trigger7.test</Link>
</None>
<None Include="..\test\trigger8.test">
<Link>test\trigger8.test</Link>
</None>
<None Include="..\test\trigger9.test">
<Link>test\trigger9.test</Link>
</None>
<None Include="..\test\triggerA.test">
<Link>test\triggerA.test</Link>
</None>
<None Include="..\test\triggerB.test">
<Link>test\triggerB.test</Link>
</None>
<None Include="..\test\triggerC.test">
<Link>test\triggerC.test</Link>
</None>
<None Include="..\test\triggerD.test">
<Link>test\triggerD.test</Link>
</None>
<None Include="..\test\types.test">
<Link>test\types.test</Link>
</None>
<None Include="..\test\types2.test">
<Link>test\types2.test</Link>
</None>
<None Include="..\test\types3.test">
<Link>test\types3.test</Link>
</None>
<None Include="..\test\unique.test">
<Link>test\unique.test</Link>
</None>
<None Include="..\test\unordered.test">
<Link>test\unordered.test</Link>
</None>
<None Include="..\test\update.test">
<Link>test\update.test</Link>
</None>
<None Include="..\test\uri.test">
<Link>test\uri.test</Link>
</None>
<None Include="..\test\utf16align.test">
<Link>test\utf16align.test</Link>
</None>
<None Include="..\test\vacuum.test">
<Link>test\vacuum.test</Link>
</None>
<None Include="..\test\vacuum2.test">
<Link>test\vacuum2.test</Link>
</None>
<None Include="..\test\vacuum3.test">
<Link>test\vacuum3.test</Link>
</None>
<None Include="..\test\vacuum4.test">
<Link>test\vacuum4.test</Link>
</None>
<None Include="..\test\varint.test">
<Link>test\varint.test</Link>
</None>
<None Include="..\test\view.test">
<Link>test\view.test</Link>
</None>
<None Include="..\test\vtab1.test">
<Link>test\vtab1.test</Link>
</None>
<None Include="..\test\vtab2.test">
<Link>test\vtab2.test</Link>
</None>
<None Include="..\test\vtab3.test">
<Link>test\vtab3.test</Link>
</None>
<None Include="..\test\vtab4.test">
<Link>test\vtab4.test</Link>
</None>
<None Include="..\test\vtab5.test">
<Link>test\vtab5.test</Link>
</None>
<None Include="..\test\vtab6.test">
<Link>test\vtab6.test</Link>
</None>
<None Include="..\test\vtab7.test">
<Link>test\vtab7.test</Link>
</None>
<None Include="..\test\vtab8.test">
<Link>test\vtab8.test</Link>
</None>
<None Include="..\test\vtab9.test">
<Link>test\vtab9.test</Link>
</None>
<None Include="..\test\vtabA.test">
<Link>test\vtabA.test</Link>
</None>
<None Include="..\test\vtabB.test">
<Link>test\vtabB.test</Link>
</None>
<None Include="..\test\vtabC.test">
<Link>test\vtabC.test</Link>
</None>
<None Include="..\test\vtabD.test">
<Link>test\vtabD.test</Link>
</None>
<None Include="..\test\vtabE.test">
<Link>test\vtabE.test</Link>
</None>
<None Include="..\test\vtab_alter.test">
<Link>test\vtab_alter.test</Link>
</None>
<None Include="..\test\vtab_err.test">
<Link>test\vtab_err.test</Link>
</None>
<None Include="..\test\vtab_shared.test">
<Link>test\vtab_shared.test</Link>
</None>
<None Include="..\test\wal.test">
<Link>test\wal.test</Link>
</None>
<None Include="..\test\wal2.test">
<Link>test\wal2.test</Link>
</None>
<None Include="..\test\wal3.test">
<Link>test\wal3.test</Link>
</None>
<None Include="..\test\wal4.test">
<Link>test\wal4.test</Link>
</None>
<None Include="..\test\wal5.test">
<Link>test\wal5.test</Link>
</None>
<None Include="..\test\wal6.test">
<Link>test\wal6.test</Link>
</None>
<None Include="..\test\walbak.test">
<Link>test\walbak.test</Link>
</None>
<None Include="..\test\walbig.test">
<Link>test\walbig.test</Link>
</None>
<None Include="..\test\walcksum.test">
<Link>test\walcksum.test</Link>
</None>
<None Include="..\test\walcrash.test">
<Link>test\walcrash.test</Link>
</None>
<None Include="..\test\walcrash2.test">
<Link>test\walcrash2.test</Link>
</None>
<None Include="..\test\walfault.test">
<Link>test\walfault.test</Link>
</None>
<None Include="..\test\walhook.test">
<Link>test\walhook.test</Link>
</None>
<None Include="..\test\walmode.test">
<Link>test\walmode.test</Link>
</None>
<None Include="..\test\walnoshm.test">
<Link>test\walnoshm.test</Link>
</None>
<None Include="..\test\walshared.test">
<Link>test\walshared.test</Link>
</None>
<None Include="..\test\walslow.test">
<Link>test\walslow.test</Link>
</None>
<None Include="..\test\walthread.test">
<Link>test\walthread.test</Link>
</None>
<None Include="..\test\wal_common.tcl">
<Link>test\wal_common.tcl</Link>
</None>
<None Include="..\test\where.test">
<Link>test\where.test</Link>
</None>
<None Include="..\test\where2.test">
<Link>test\where2.test</Link>
</None>
<None Include="..\test\where3.test">
<Link>test\where3.test</Link>
</None>
<None Include="..\test\where4.test">
<Link>test\where4.test</Link>
</None>
<None Include="..\test\where5.test">
<Link>test\where5.test</Link>
</None>
<None Include="..\test\where6.test">
<Link>test\where6.test</Link>
</None>
<None Include="..\test\where7.test">
<Link>test\where7.test</Link>
</None>
<None Include="..\test\where8.test">
<Link>test\where8.test</Link>
</None>
<None Include="..\test\where8m.test">
<Link>test\where8m.test</Link>
</None>
<None Include="..\test\where9.test">
<Link>test\where9.test</Link>
</None>
<None Include="..\test\whereA.test">
<Link>test\whereA.test</Link>
</None>
<None Include="..\test\whereB.test">
<Link>test\whereB.test</Link>
</None>
<None Include="..\test\wherelimit.test">
<Link>test\wherelimit.test</Link>
</None>
<None Include="..\test\zeroblob.test">
<Link>test\zeroblob.test</Link>
</None>
<None Include="..\test\^testscripts.test">
<Link>test\^testscripts.test</Link>
</None>
<None Include="..\test\_C#SQLite.test">
<Link>test\_C#SQLite.test</Link>
</None>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
<Visible>False</Visible>
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
<Visible>False</Visible>
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Content Include="..\test\crashtest1.c">
<Link>test\crashtest1.c</Link>
</Content>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PostBuildEvent>call "$(DevEnvDir)..\tools\vsvars32.bat"
editbin /stack:4000000 “$(TargetPath)”</PostBuildEvent>
</PropertyGroup>
</Project>
/trunk/testfixture/testfixture.sln
@@ -0,0 +1,32 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testfixture", "testfixture.csproj", "{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Debug|x64.ActiveCfg = Debug|x64
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Debug|x64.Build.0 = Debug|x64
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Debug|x86.ActiveCfg = Debug|x86
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Debug|x86.Build.0 = Debug|x86
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Release|Any CPU.Build.0 = Release|Any CPU
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Release|x64.ActiveCfg = Release|x64
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Release|x64.Build.0 = Release|x64
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Release|x86.ActiveCfg = Release|x86
{FDA6FB30-1601-4C64-85C1-49C7AD3C78DD}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal