/testfixture/src/tclsqlite_c.cs
C# | 4427 lines | 2980 code | 291 blank | 1156 comment | 628 complexity | 25533ef33e9a5de69148b1e48b9509b1 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- 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 equival…
Large files files are truncated, but you can click here to view the full file