wasCSharpSQLite – Rev 1

Subversion Repositories:
Rev:
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
}