Index: System.Data.SQLite/SQLite3.cs ================================================================== --- System.Data.SQLite/SQLite3.cs +++ System.Data.SQLite/SQLite3.cs @@ -10,10 +10,11 @@ using System; #if DEBUG using System.Diagnostics; #endif using System.Runtime.InteropServices; + using System.Text; #if !PLATFORM_COMPACTFRAMEWORK [UnmanagedFunctionPointer(CallingConvention.Cdecl)] #endif internal delegate void SQLiteLogCallback(IntPtr puser, int err_code, IntPtr message); @@ -209,11 +210,11 @@ internal override bool IsOpen() { return (_sql != null); } - internal override void Open(string strFilename, SQLiteOpenFlagsEnum flags, int maxPoolSize, bool usePool) + internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool) { if (_sql != null) return; _usePool = usePool; if (usePool) @@ -225,13 +226,13 @@ if (_sql == null) { IntPtr db; #if !SQLITE_STANDARD - int n = UnsafeNativeMethods.sqlite3_open_interop(ToUTF8(strFilename), (int)flags, out db); + int n = UnsafeNativeMethods.sqlite3_open_interop(ToUTF8(strFilename), (int)openFlags, out db); #else - int n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), out db, (int)flags, IntPtr.Zero); + int n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), out db, (int)openFlags, IntPtr.Zero); #endif #if DEBUG Trace.WriteLine(String.Format("Open: {0}", db)); #endif @@ -240,11 +241,11 @@ _sql = db; } // Bind functions to this connection. If any previous functions of the same name // were already bound, then the new bindings replace the old. - _functionsArray = SQLiteFunction.BindFunctions(this); + _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); SetTimeout(0); } internal override void ClearPool() { @@ -366,18 +367,22 @@ strSql = strSql.Replace( String.Format("{0}.", baseSchemaName), String.Empty); } } - if ((cnn != null) && - ((cnn.Flags & SQLiteConnectionFlags.LogPrepare) == SQLiteConnectionFlags.LogPrepare)) + SQLiteConnectionFlags flags = + (cnn != null) ? cnn.Flags : SQLiteConnectionFlags.Default; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogPrepare) == SQLiteConnectionFlags.LogPrepare) { if ((strSql == null) || (strSql.Length == 0) || (strSql.Trim().Length == 0)) SQLiteLog.LogMessage(0, "Preparing {}..."); else SQLiteLog.LogMessage(0, String.Format("Preparing {{{0}}}...", strSql)); } +#endif IntPtr stmt = IntPtr.Zero; IntPtr ptr = IntPtr.Zero; int len = 0; int n = 17; @@ -478,149 +483,376 @@ if (n > 0) throw new SQLiteException(n, SQLiteLastError()); strRemain = UTF8ToString(ptr, len); - if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous); + if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous); return cmd; } finally { handle.Free(); } } - internal override void Bind_Double(SQLiteStatement stmt, int index, double value) - { -#if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_double(stmt._sqlite_stmt, index, value); -#else - int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value); -#endif - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override void Bind_Int32(SQLiteStatement stmt, int index, int value) - { - int n = UnsafeNativeMethods.sqlite3_bind_int(stmt._sqlite_stmt, index, value); - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override void Bind_UInt32(SQLiteStatement stmt, int index, uint value) - { - int n = UnsafeNativeMethods.sqlite3_bind_uint(stmt._sqlite_stmt, index, value); - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override void Bind_Int64(SQLiteStatement stmt, int index, long value) - { -#if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value); -#else - int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value); -#endif - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override void Bind_UInt64(SQLiteStatement stmt, int index, ulong value) - { -#if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_uint64(stmt._sqlite_stmt, index, value); -#else - int n = UnsafeNativeMethods.sqlite3_bind_uint64_interop(stmt._sqlite_stmt, index, ref value); -#endif - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override void Bind_Text(SQLiteStatement stmt, int index, string value) - { - byte[] b = ToUTF8(value); - int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1)); - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override void Bind_DateTime(SQLiteStatement stmt, int index, DateTime dt) - { +#if !PLATFORM_COMPACTFRAMEWORK + protected static void LogBind(SQLiteStatementHandle handle, int index) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Binding statement {0} paramter #{1} as NULL...", + handleIntPtr, index)); + } + + protected static void LogBind(SQLiteStatementHandle handle, int index, ValueType value) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Binding statement {0} paramter #{1} as type {2} with value {{{3}}}...", + handleIntPtr, index, value.GetType(), value)); + } + + private static string FormatDateTime(DateTime value) + { + StringBuilder result = new StringBuilder(); + + result.Append(value.ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK")); + result.Append(' '); + result.Append(value.Kind); + result.Append(' '); + result.Append(value.Ticks); + + return result.ToString(); + } + + protected static void LogBind(SQLiteStatementHandle handle, int index, DateTime value) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Binding statement {0} paramter #{1} as type {2} with value {{{3}}}...", + handleIntPtr, index, typeof(DateTime), FormatDateTime(value))); + } + + protected static void LogBind(SQLiteStatementHandle handle, int index, string value) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Binding statement {0} paramter #{1} as type {2} with value {{{3}}}...", + handleIntPtr, index, typeof(String), (value != null) ? value : "")); + } + + private static string ToHexadecimalString( + byte[] array + ) + { + if (array == null) + return null; + + StringBuilder result = new StringBuilder(array.Length * 2); + + int length = array.Length; + + for (int index = 0; index < length; index++) + result.Append(array[index].ToString("x2")); + + return result.ToString(); + } + + protected static void LogBind(SQLiteStatementHandle handle, int index, byte[] value) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Binding statement {0} paramter #{1} as type {2} with value {{{3}}}...", + handleIntPtr, index, typeof(Byte[]), (value != null) ? ToHexadecimalString(value) : "")); + } +#endif + + internal override void Bind_Double(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, double value) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } + + int n = UnsafeNativeMethods.sqlite3_bind_double(handle, index, value); +#else + int n = UnsafeNativeMethods.sqlite3_bind_double_interop(handle, index, ref value); +#endif + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override void Bind_Int32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, int value) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } +#endif + + int n = UnsafeNativeMethods.sqlite3_bind_int(handle, index, value); + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override void Bind_UInt32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, uint value) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } +#endif + + int n = UnsafeNativeMethods.sqlite3_bind_uint(handle, index, value); + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override void Bind_Int64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, long value) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } + + int n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value); +#else + int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value); +#endif + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override void Bind_UInt64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, ulong value) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } + + int n = UnsafeNativeMethods.sqlite3_bind_uint64(handle, index, value); +#else + int n = UnsafeNativeMethods.sqlite3_bind_uint64_interop(handle, index, ref value); +#endif + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } +#endif + + byte[] b = ToUTF8(value); + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, b); + } +#endif + + int n = UnsafeNativeMethods.sqlite3_bind_text(handle, index, b, b.Length - 1, (IntPtr)(-1)); + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, dt); + } +#endif + switch (_datetimeFormat) { case SQLiteDateFormats.Ticks: { long value = dt.Ticks; #if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value); + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } + + int n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value); #else - int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value); + int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value); #endif if (n > 0) throw new SQLiteException(n, SQLiteLastError()); break; } case SQLiteDateFormats.JulianDay: { double value = ToJulianDay(dt); #if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_double(stmt._sqlite_stmt, index, value); + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } + + int n = UnsafeNativeMethods.sqlite3_bind_double(handle, index, value); #else - int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value); + int n = UnsafeNativeMethods.sqlite3_bind_double_interop(handle, index, ref value); #endif if (n > 0) throw new SQLiteException(n, SQLiteLastError()); break; } case SQLiteDateFormats.UnixEpoch: { long value = Convert.ToInt64(dt.Subtract(UnixEpoch).TotalSeconds); #if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value); + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } + + int n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value); #else - int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value); + int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value); #endif if (n > 0) throw new SQLiteException(n, SQLiteLastError()); break; } default: { byte[] b = ToUTF8(dt); - int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1)); + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, b); + } +#endif + + int n = UnsafeNativeMethods.sqlite3_bind_text(handle, index, b, b.Length - 1, (IntPtr)(-1)); if (n > 0) throw new SQLiteException(n, SQLiteLastError()); break; } } } - internal override void Bind_Blob(SQLiteStatement stmt, int index, byte[] blobData) - { - int n = UnsafeNativeMethods.sqlite3_bind_blob(stmt._sqlite_stmt, index, blobData, blobData.Length, (IntPtr)(-1)); - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override void Bind_Null(SQLiteStatement stmt, int index) - { - int n = UnsafeNativeMethods.sqlite3_bind_null(stmt._sqlite_stmt, index); - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - } - - internal override int Bind_ParamCount(SQLiteStatement stmt) - { - return UnsafeNativeMethods.sqlite3_bind_parameter_count(stmt._sqlite_stmt); - } - - internal override string Bind_ParamName(SQLiteStatement stmt, int index) - { + internal override void Bind_Blob(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, byte[] blobData) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, blobData); + } +#endif + + int n = UnsafeNativeMethods.sqlite3_bind_blob(handle, index, blobData, blobData.Length, (IntPtr)(-1)); + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override void Bind_Null(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index); + } +#endif + + int n = UnsafeNativeMethods.sqlite3_bind_null(handle, index); + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + } + + internal override int Bind_ParamCount(SQLiteStatement stmt, SQLiteConnectionFlags flags) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + int value = UnsafeNativeMethods.sqlite3_bind_parameter_count(handle); + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Statement {0} paramter count is {1}.", + handleIntPtr, value)); + } +#endif + + return value; + } + + internal override string Bind_ParamName(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index) + { + SQLiteStatementHandle handle = stmt._sqlite_stmt; + string name; + #if !SQLITE_STANDARD - int len; - return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name_interop(stmt._sqlite_stmt, index, out len), len); + int len; + name = UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name_interop(handle, index, out len), len); #else - return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(stmt._sqlite_stmt, index), -1); + name = UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(handle, index), -1); +#endif + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Statement {0} paramter #{1} name is {{{2}}}.", + handleIntPtr, index, name)); + } #endif + + return name; } - internal override int Bind_ParamIndex(SQLiteStatement stmt, string paramName) + internal override int Bind_ParamIndex(SQLiteStatement stmt, SQLiteConnectionFlags flags, string paramName) { - return UnsafeNativeMethods.sqlite3_bind_parameter_index(stmt._sqlite_stmt, ToUTF8(paramName)); + SQLiteStatementHandle handle = stmt._sqlite_stmt; + int index = UnsafeNativeMethods.sqlite3_bind_parameter_index(handle, ToUTF8(paramName)); + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + IntPtr handleIntPtr = handle; + + SQLiteLog.LogMessage(0, String.Format( + "Statement {0} paramter index of name {{{1}}} is #{2}.", + handleIntPtr, paramName, index)); + } +#endif + + return index; } internal override int ColumnCount(SQLiteStatement stmt) { return UnsafeNativeMethods.sqlite3_column_count(stmt._sqlite_stmt); Index: System.Data.SQLite/SQLite3_UTF16.cs ================================================================== --- System.Data.SQLite/SQLite3_UTF16.cs +++ System.Data.SQLite/SQLite3_UTF16.cs @@ -84,13 +84,13 @@ if (nbytelen == -1) return Marshal.PtrToStringUni(b); else return Marshal.PtrToStringUni(b, nbytelen / 2); - } - - internal override void Open(string strFilename, SQLiteOpenFlagsEnum flags, int maxPoolSize, bool usePool) + } + + internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool) { if (_sql != null) return; _usePool = usePool; if (usePool) @@ -102,11 +102,11 @@ if (_sql == null) { IntPtr db; #if !SQLITE_STANDARD - int n = UnsafeNativeMethods.sqlite3_open16_interop(ToUTF8(strFilename), (int)flags, out db); + int n = UnsafeNativeMethods.sqlite3_open16_interop(ToUTF8(strFilename), (int)openFlags, out db); #else if ((flags & SQLiteOpenFlagsEnum.Create) == 0 && System.IO.File.Exists(strFilename) == false) throw new SQLiteException((int)SQLiteErrorCode.CantOpen, strFilename); int n = UnsafeNativeMethods.sqlite3_open16(strFilename, out db); @@ -117,66 +117,56 @@ #endif if (n > 0) throw new SQLiteException(n, null); _sql = db; - } - _functionsArray = SQLiteFunction.BindFunctions(this); - } - - internal override void Bind_DateTime(SQLiteStatement stmt, int index, DateTime dt) + } + _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); + } + + internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt) { switch (_datetimeFormat) { case SQLiteDateFormats.Ticks: - { - long value = dt.Ticks; - -#if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value); -#else - int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value); -#endif - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - break; - } case SQLiteDateFormats.JulianDay: - { - double value = ToJulianDay(dt); - -#if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_double(stmt._sqlite_stmt, index, value); -#else - int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value); -#endif - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); - break; - } case SQLiteDateFormats.UnixEpoch: { - long value = Convert.ToInt64(dt.Subtract(UnixEpoch).TotalSeconds); - -#if !PLATFORM_COMPACTFRAMEWORK - int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value); -#else - int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value); -#endif - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + base.Bind_DateTime(stmt, flags, index, dt); break; } default: { - Bind_Text(stmt, index, ToString(dt)); +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + SQLiteStatementHandle handle = + (stmt != null) ? stmt._sqlite_stmt : null; + + LogBind(handle, index, dt); + } +#endif + + Bind_Text(stmt, flags, index, ToString(dt)); break; } } - } - - internal override void Bind_Text(SQLiteStatement stmt, int index, string value) + } + + internal override void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value) { - int n = UnsafeNativeMethods.sqlite3_bind_text16(stmt._sqlite_stmt, index, value, value.Length * 2, (IntPtr)(-1)); - if (n > 0) throw new SQLiteException(n, SQLiteLastError()); + SQLiteStatementHandle handle = stmt._sqlite_stmt; + +#if !PLATFORM_COMPACTFRAMEWORK + if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind) + { + LogBind(handle, index, value); + } +#endif + + int n = UnsafeNativeMethods.sqlite3_bind_text16(handle, index, value, value.Length * 2, (IntPtr)(-1)); + if (n > 0) throw new SQLiteException(n, SQLiteLastError()); } internal override DateTime GetDateTime(SQLiteStatement stmt, int index) { return ToDateTime(GetText(stmt, index)); Index: System.Data.SQLite/SQLiteBase.cs ================================================================== --- System.Data.SQLite/SQLiteBase.cs +++ System.Data.SQLite/SQLiteBase.cs @@ -56,14 +56,15 @@ /// /// Implementers should call SQLiteFunction.BindFunctions() and save the array after opening a connection /// to bind all attributed user-defined functions and collating sequences to the new connection. /// /// The filename of the database to open. SQLite automatically creates it if it doesn't exist. - /// The open flags to use when creating the connection + /// The flags associated with the parent connection object + /// The open flags to use when creating the connection /// The maximum size of the pool for the given filename /// If true, the connection can be pulled from the connection pool - internal abstract void Open(string strFilename, SQLiteOpenFlagsEnum flags, int maxPoolSize, bool usePool); + internal abstract void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool); /// /// Closes the currently-open database. /// /// /// After the database has been closed implemeters should call SQLiteFunction.UnbindFunctions() to deallocate all interop allocated @@ -111,23 +112,23 @@ /// The statement to reset /// Returns -1 if the schema changed while resetting, 0 if the reset was sucessful or 6 (SQLITE_LOCKED) if the reset failed due to a lock internal abstract int Reset(SQLiteStatement stmt); internal abstract void Cancel(); - internal abstract void Bind_Double(SQLiteStatement stmt, int index, double value); - internal abstract void Bind_Int32(SQLiteStatement stmt, int index, Int32 value); - internal abstract void Bind_UInt32(SQLiteStatement stmt, int index, UInt32 value); - internal abstract void Bind_Int64(SQLiteStatement stmt, int index, Int64 value); - internal abstract void Bind_UInt64(SQLiteStatement stmt, int index, UInt64 value); - internal abstract void Bind_Text(SQLiteStatement stmt, int index, string value); - internal abstract void Bind_Blob(SQLiteStatement stmt, int index, byte[] blobData); - internal abstract void Bind_DateTime(SQLiteStatement stmt, int index, DateTime dt); - internal abstract void Bind_Null(SQLiteStatement stmt, int index); - - internal abstract int Bind_ParamCount(SQLiteStatement stmt); - internal abstract string Bind_ParamName(SQLiteStatement stmt, int index); - internal abstract int Bind_ParamIndex(SQLiteStatement stmt, string paramName); + internal abstract void Bind_Double(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, double value); + internal abstract void Bind_Int32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, Int32 value); + internal abstract void Bind_UInt32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, UInt32 value); + internal abstract void Bind_Int64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, Int64 value); + internal abstract void Bind_UInt64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, UInt64 value); + internal abstract void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value); + internal abstract void Bind_Blob(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, byte[] blobData); + internal abstract void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt); + internal abstract void Bind_Null(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index); + + internal abstract int Bind_ParamCount(SQLiteStatement stmt, SQLiteConnectionFlags flags); + internal abstract string Bind_ParamName(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index); + internal abstract int Bind_ParamIndex(SQLiteStatement stmt, SQLiteConnectionFlags flags, string paramName); internal abstract int ColumnCount(SQLiteStatement stmt); internal abstract string ColumnName(SQLiteStatement stmt, int index); internal abstract TypeAffinity ColumnAffinity(SQLiteStatement stmt, int index); internal abstract string ColumnType(SQLiteStatement stmt, int index, out TypeAffinity nAffinity); @@ -383,10 +384,31 @@ /// /// Enable logging of all SQL statements to be prepared. /// LogPrepare = 0x1, + /// + /// Enable logging of all bound parameter types and raw values. + /// + LogPreBind = 0x2, + + /// + /// Enable logging of all bound parameter strongly typed values. + /// + LogBind = 0x4, + + /// + /// Enable logging of all exceptions caught from user-provided + /// managed code called from native code via delegates. + /// + LogCallbackException = 0x8, + + /// + /// Enable all logging. + /// + LogAll = LogPrepare | LogPreBind | LogBind | LogCallbackException, + /// /// The default extra flags for new connections. /// Default = None } Index: System.Data.SQLite/SQLiteConnection.cs ================================================================== --- System.Data.SQLite/SQLiteConnection.cs +++ System.Data.SQLite/SQLiteConnection.cs @@ -939,11 +939,11 @@ else { flags |= SQLiteOpenFlagsEnum.ReadWrite; } - _sql.Open(fileName, flags, maxPoolSize, usePooling); + _sql.Open(fileName, _flags, flags, maxPoolSize, usePooling); _binaryGuid = (SQLiteConvert.ToBoolean(FindKey(opts, "BinaryGUID", Boolean.TrueString)) == true); string password = FindKey(opts, "Password", null); Index: System.Data.SQLite/SQLiteConvert.cs ================================================================== --- System.Data.SQLite/SQLiteConvert.cs +++ System.Data.SQLite/SQLiteConvert.cs @@ -74,10 +74,22 @@ "yyyy-MM-dd", "yyyyMMdd", "yy-MM-dd" }; + /// + /// The internal default format for UTC DateTime values when converting + /// to a string. + /// + private static readonly string _datetimeFormatUtc = _datetimeFormats[5]; + + /// + /// The internal default format for local DateTime values when converting + /// to a string. + /// + private static readonly string _datetimeFormatLocal = _datetimeFormats[19]; + /// /// An UTF-8 Encoding instance, so we can convert strings to and from UTF-8 /// private static Encoding _utf8 = new UTF8Encoding(); /// @@ -347,10 +359,23 @@ /// The JulianDay value the Datetime represents public static double ToJulianDay(DateTime value) { return value.ToOADate() + OleAutomationEpochAsJulianDay; } + + /// + /// Returns the default DateTime format string to use for the specified + /// DateTimeKind. + /// + /// The DateTimeKind to use. + /// + /// The default DateTime format string to use for the specified DateTimeKind. + /// + private static string GetDateTimeKindFormat(DateTimeKind kind) + { + return (kind == DateTimeKind.Utc) ? _datetimeFormatUtc : _datetimeFormatLocal; + } /// /// Converts a DateTime to a string value, using the current DateTimeFormat specified for the connection when it was opened. /// /// The DateTime value to convert @@ -357,27 +382,28 @@ /// Either a string containing the long integer number of 100-nanosecond units since System.DateTime.MinValue, a /// Julian day double, an integer number of seconds since the Unix epoch, a culture-independent formatted date and time /// string, a formatted date and time string in the current culture, or an ISO8601-format date/time string. public string ToString(DateTime dateValue) { - switch (_datetimeFormat) - { - case SQLiteDateFormats.Ticks: - return dateValue.Ticks.ToString(CultureInfo.InvariantCulture); - case SQLiteDateFormats.JulianDay: - return ToJulianDay(dateValue).ToString(CultureInfo.InvariantCulture); - case SQLiteDateFormats.UnixEpoch: - return ((long)(dateValue.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond)).ToString(); - case SQLiteDateFormats.InvariantCulture: - return dateValue.ToString(FullFormat, CultureInfo.InvariantCulture); - case SQLiteDateFormats.CurrentCulture: - return dateValue.ToString(FullFormat, CultureInfo.CurrentCulture); - default: - return (dateValue.Kind == DateTimeKind.Utc) ? - dateValue.ToString(_datetimeFormats[5], CultureInfo.InvariantCulture) : // include "Z" - dateValue.ToString(_datetimeFormats[19], CultureInfo.InvariantCulture); - } + switch (_datetimeFormat) + { + case SQLiteDateFormats.Ticks: + return dateValue.Ticks.ToString(CultureInfo.InvariantCulture); + case SQLiteDateFormats.JulianDay: + return ToJulianDay(dateValue).ToString(CultureInfo.InvariantCulture); + case SQLiteDateFormats.UnixEpoch: + return ((long)(dateValue.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond)).ToString(); + case SQLiteDateFormats.InvariantCulture: + return dateValue.ToString(FullFormat, CultureInfo.InvariantCulture); + case SQLiteDateFormats.CurrentCulture: + return dateValue.ToString(FullFormat, CultureInfo.CurrentCulture); + default: + return (dateValue.Kind == DateTimeKind.Unspecified) ? + DateTime.SpecifyKind(dateValue, _datetimeKind).ToString( + GetDateTimeKindFormat(_datetimeKind), CultureInfo.InvariantCulture) : + dateValue.ToString(GetDateTimeKindFormat(dateValue.Kind), CultureInfo.InvariantCulture); + } } /// /// Internal function to convert a UTF-8 encoded IntPtr of the specified length to a DateTime. /// Index: System.Data.SQLite/SQLiteFunction.cs ================================================================== --- System.Data.SQLite/SQLiteFunction.cs +++ System.Data.SQLite/SQLiteFunction.cs @@ -32,21 +32,39 @@ { private class AggregateData { internal int _count = 1; internal object _data; - } + } + + ///////////////////////////////////////////////////////////////////////// + + #region Private Constants + /// + /// The error code used for logging exceptions caught in user-provided + /// code. + /// + private const int COR_E_EXCEPTION = unchecked((int)0x80131500); + #endregion + + ///////////////////////////////////////////////////////////////////////// /// /// The base connection this function is attached to /// internal SQLiteBase _base; /// /// Internal array used to keep track of aggregate function context data - /// - private Dictionary _contextDataList; + /// + private Dictionary _contextDataList; + + /// + /// The connection flags associated with this object (this should be the + /// same value as the flags associated with the parent connection object). + /// + private SQLiteConnectionFlags _flags; /// /// Holds a reference to the callback function for user functions /// private SQLiteCallback _InvokeFunc; @@ -78,11 +96,11 @@ /// /// Internal constructor, initializes the function's internal variables. /// protected SQLiteFunction() { - _contextDataList = new Dictionary(); + _contextDataList = new Dictionary(); } /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable Members @@ -125,24 +143,26 @@ // dispose managed resources here... //////////////////////////////////// IDisposable disp; - foreach (KeyValuePair kv in _contextDataList) + foreach (KeyValuePair kv in _contextDataList) { disp = kv.Value._data as IDisposable; if (disp != null) disp.Dispose(); } _contextDataList.Clear(); + _contextDataList = null; + + _flags = SQLiteConnectionFlags.None; _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; - _contextDataList = null; } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// @@ -347,95 +367,271 @@ return; } } /// - /// Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method. + /// Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method. + /// WARNING: Must not throw exceptions. /// /// A raw context pointer /// Number of arguments passed in - /// A pointer to the array of arguments - internal void ScalarCallback(IntPtr context, int nArgs, IntPtr argsptr) - { - _context = context; - SetReturnValue(context, Invoke(ConvertParams(nArgs, argsptr))); + /// A pointer to the array of arguments + internal void ScalarCallback(IntPtr context, int nArgs, IntPtr argsptr) + { + try + { + _context = context; + SetReturnValue(context, + Invoke(ConvertParams(nArgs, argsptr))); /* throw */ + } +#if !PLATFORM_COMPACTFRAMEWORK + catch (Exception e) /* NOTE: Must catch ALL. */ + { + try + { + if ((_flags & SQLiteConnectionFlags.LogCallbackException) == + SQLiteConnectionFlags.LogCallbackException) + { + SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( + "Caught exception in \"Invoke\" method: {0}", + e)); /* throw */ + } + } + catch + { + // do nothing. + } + } +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif } /// - /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function. + /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function. + /// WARNING: Must not throw exceptions. /// /// Not used /// Length of the string pv1 /// Pointer to the first string to compare /// Length of the string pv2 /// Pointer to the second string to compare /// Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater - /// than the second. - internal int CompareCallback(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2) - { - return Compare(SQLiteConvert.UTF8ToString(ptr1, len1), SQLiteConvert.UTF8ToString(ptr2, len2)); - } - - internal int CompareCallback16(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2) - { - return Compare(SQLite3_UTF16.UTF16ToString(ptr1, len1), SQLite3_UTF16.UTF16ToString(ptr2, len2)); + /// than the second. Returns 0 if an exception is caught. + internal int CompareCallback(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2) + { + try + { + return Compare(SQLiteConvert.UTF8ToString(ptr1, len1), + SQLiteConvert.UTF8ToString(ptr2, len2)); /* throw */ + } +#if !PLATFORM_COMPACTFRAMEWORK + catch (Exception e) /* NOTE: Must catch ALL. */ + { + try + { + if ((_flags & SQLiteConnectionFlags.LogCallbackException) == + SQLiteConnectionFlags.LogCallbackException) + { + SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( + "Caught exception in \"Compare\" method: {0}", + e)); /* throw */ + } + } + catch + { + // do nothing. + } + } +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif + + return 0; + } + + /// + /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function. + /// WARNING: Must not throw exceptions. + /// + /// Not used + /// Length of the string pv1 + /// Pointer to the first string to compare + /// Length of the string pv2 + /// Pointer to the second string to compare + /// Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater + /// than the second. Returns 0 if an exception is caught. + internal int CompareCallback16(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2) + { + try + { + return Compare(SQLite3_UTF16.UTF16ToString(ptr1, len1), + SQLite3_UTF16.UTF16ToString(ptr2, len2)); /* throw */ + } +#if !PLATFORM_COMPACTFRAMEWORK + catch (Exception e) /* NOTE: Must catch ALL. */ + { + try + { + if ((_flags & SQLiteConnectionFlags.LogCallbackException) == + SQLiteConnectionFlags.LogCallbackException) + { + SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( + "Caught exception in \"Compare\" method: {0}", + e)); /* throw */ + } + } + catch + { + // do nothing. + } + } +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif + + return 0; } /// - /// The internal aggregate Step function callback, which wraps the raw context pointer and calls the virtual Step() method. + /// The internal aggregate Step function callback, which wraps the raw context pointer and calls the virtual Step() method. + /// WARNING: Must not throw exceptions. /// /// /// This function takes care of doing the lookups and getting the important information put together to call the Step() function. /// That includes pulling out the user's contextData and updating it after the call is made. We use a sorted list for this so /// binary searches can be done to find the data. /// /// A raw context pointer /// Number of arguments passed in - /// A pointer to the array of arguments - internal void StepCallback(IntPtr context, int nArgs, IntPtr argsptr) - { - long nAux; - AggregateData data; - - nAux = (long)_base.AggregateContext(context); - if (_contextDataList.TryGetValue(nAux, out data) == false) - { - data = new AggregateData(); - _contextDataList[nAux] = data; - } - - try - { - _context = context; - Step(ConvertParams(nArgs, argsptr), data._count, ref data._data); - } - finally - { - data._count++; - } + /// A pointer to the array of arguments + internal void StepCallback(IntPtr context, int nArgs, IntPtr argsptr) + { + try + { + AggregateData data = null; + + if (_base != null) + { + IntPtr nAux = _base.AggregateContext(context); + + if ((_contextDataList != null) && + !_contextDataList.TryGetValue(nAux, out data)) + { + data = new AggregateData(); + _contextDataList[nAux] = data; + } + } + + if (data == null) + data = new AggregateData(); + + try + { + _context = context; + Step(ConvertParams(nArgs, argsptr), + data._count, ref data._data); /* throw */ + } + finally + { + data._count++; + } + } +#if !PLATFORM_COMPACTFRAMEWORK + catch (Exception e) /* NOTE: Must catch ALL. */ + { + try + { + if ((_flags & SQLiteConnectionFlags.LogCallbackException) == + SQLiteConnectionFlags.LogCallbackException) + { + SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( + "Caught exception in \"Step\" method: {1}", + e)); /* throw */ + } + } + catch + { + // do nothing. + } + } +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif } /// - /// An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method. + /// An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method. + /// WARNING: Must not throw exceptions. /// - /// A raw context pointer - internal void FinalCallback(IntPtr context) - { - long n = (long)_base.AggregateContext(context); - object obj = null; - - if (_contextDataList.ContainsKey(n)) - { - obj = _contextDataList[n]._data; - _contextDataList.Remove(n); - } - - _context = context; - SetReturnValue(context, Final(obj)); - - IDisposable disp = obj as IDisposable; - if (disp != null) disp.Dispose(); + /// A raw context pointer + internal void FinalCallback(IntPtr context) + { + try + { + object obj = null; + + if (_base != null) + { + IntPtr n = _base.AggregateContext(context); + AggregateData aggData; + + if ((_contextDataList != null) && + _contextDataList.TryGetValue(n, out aggData)) + { + obj = aggData._data; + _contextDataList.Remove(n); + } + } + + try + { + _context = context; + SetReturnValue(context, Final(obj)); /* throw */ + } + finally + { + IDisposable disp = obj as IDisposable; + if (disp != null) disp.Dispose(); /* throw */ + } + } +#if !PLATFORM_COMPACTFRAMEWORK + catch (Exception e) /* NOTE: Must catch ALL. */ + { + try + { + if ((_flags & SQLiteConnectionFlags.LogCallbackException) == + SQLiteConnectionFlags.LogCallbackException) + { + SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( + "Caught exception in \"Final\" method: {1}", + e)); /* throw */ + } + } + catch + { + // do nothing. + } + } +#else + catch /* NOTE: Must catch ALL. */ + { + // do nothing (Windows CE). + } +#endif } /// /// Using reflection, enumerate all assemblies in the current appdomain looking for classes that /// have a SQLiteFunctionAttribute attribute, and registering them accordingly. @@ -537,21 +733,24 @@ /// /// /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// - /// The base object on which the functions are to bind + /// The base object on which the functions are to bind + /// The flags associated with the parent connection object /// Returns an array of functions which the connection object should retain until the connection is closed. - internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase) + internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) { SQLiteFunction f; List lFunctions = new List(); foreach (SQLiteFunctionAttribute pr in _registeredFunctions) { - f = (SQLiteFunction)Activator.CreateInstance(pr._instanceType); - f._base = sqlbase; + f = (SQLiteFunction)Activator.CreateInstance(pr._instanceType); + + f._base = sqlbase; + f._flags = flags; f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SQLiteCallback(f.ScalarCallback) : null; f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(f.StepCallback) : null; f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(f.FinalCallback) : null; f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback) : null; f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback16) : null; @@ -770,8 +969,8 @@ /// The second array to compare /// -1 if c1 is less than c2, 0 if c1 is equal to c2, and 1 if c1 is greater than c2 public int Compare(char[] c1, char[] c2) { return _func._base.ContextCollateCompare(Encoding, _func._context, c1, c2); - } - } + } + } } Index: System.Data.SQLite/SQLiteStatement.cs ================================================================== --- System.Data.SQLite/SQLiteStatement.cs +++ System.Data.SQLite/SQLiteStatement.cs @@ -40,30 +40,37 @@ /// internal SQLiteParameter[] _paramValues; /// /// Command this statement belongs to (if any) /// - internal SQLiteCommand _command; + internal SQLiteCommand _command; + + /// + /// The flags associated with the parent connection object. + /// + private SQLiteConnectionFlags _flags; private string[] _types; /// /// Initializes the statement and attempts to get all information about parameters in the statement - /// - /// The base SQLite object + /// + /// The base SQLite object + /// The flags associated with the parent connection object /// The statement /// The command text for this statement - /// The previous command in a multi-statement command - internal SQLiteStatement(SQLiteBase sqlbase, SQLiteStatementHandle stmt, string strCommand, SQLiteStatement previous) + /// The previous command in a multi-statement command + internal SQLiteStatement(SQLiteBase sqlbase, SQLiteConnectionFlags flags, SQLiteStatementHandle stmt, string strCommand, SQLiteStatement previous) { _sql = sqlbase; _sqlite_stmt = stmt; - _sqlStatement = strCommand; + _sqlStatement = strCommand; + _flags = flags; // Determine parameters for this statement (if any) and prepare space for them. int nCmdStart = 0; - int n = _sql.Bind_ParamCount(this); + int n = _sql.Bind_ParamCount(this, _flags); int x; string s; if (n > 0) { @@ -72,12 +79,12 @@ _paramNames = new string[n]; _paramValues = new SQLiteParameter[n]; for (x = 0; x < n; x++) - { - s = _sql.Bind_ParamName(this, x + 1); + { + s = _sql.Bind_ParamName(this, _flags, x + 1); if (String.IsNullOrEmpty(s)) { s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart); nCmdStart++; _unnamedParameters++; @@ -186,18 +193,18 @@ return false; } /// /// Bind all parameters, making sure the caller didn't miss any - /// + /// internal void BindParameters() { if (_paramNames == null) return; int x = _paramNames.Length; for (int n = 0; n < x; n++) - { + { BindParameter(n + 1, _paramValues[n]); } } /// @@ -255,90 +262,101 @@ } } /// /// Perform the bind operation for an individual parameter - /// + /// /// The index of the parameter to bind - /// The parameter we're binding + /// The parameter we're binding private void BindParameter(int index, SQLiteParameter param) { if (param == null) throw new SQLiteException((int)SQLiteErrorCode.Error, "Insufficient parameters supplied to the command"); object obj = param.Value; - DbType objType = param.DbType; + DbType objType = param.DbType; + + if ((obj != null) && (objType == DbType.Object)) + objType = SQLiteConvert.TypeToDbType(obj.GetType()); + +#if !PLATFORM_COMPACTFRAMEWORK + if ((_flags & SQLiteConnectionFlags.LogPreBind) == SQLiteConnectionFlags.LogPreBind) + { + IntPtr handle = _sqlite_stmt; + + SQLiteLog.LogMessage(0, String.Format( + "Binding statement {0} paramter #{1} with database type {2} and raw value {{{3}}}...", + handle, index, objType, obj)); + } +#endif - if (Convert.IsDBNull(obj) || obj == null) - { - _sql.Bind_Null(this, index); + if ((obj == null) || Convert.IsDBNull(obj)) + { + _sql.Bind_Null(this, _flags, index); return; } - if (objType == DbType.Object) - objType = SQLiteConvert.TypeToDbType(obj.GetType()); - switch (objType) { case DbType.Date: case DbType.Time: case DbType.DateTime: // // NOTE: The old method (commented below) does not honor the selected date format // for the connection. - // _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, CultureInfo.CurrentCulture)); - _sql.Bind_DateTime(this, index, (obj is string) ? + // _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, CultureInfo.CurrentCulture)); + _sql.Bind_DateTime(this, _flags, index, (obj is string) ? _sql.ToDateTime((string)obj) : Convert.ToDateTime(obj, CultureInfo.CurrentCulture)); break; - case DbType.Boolean: - _sql.Bind_Int32(this, index, ToBoolean(obj, CultureInfo.CurrentCulture) ? 1 : 0); - break; - case DbType.SByte: - _sql.Bind_Int32(this, index, Convert.ToSByte(obj, CultureInfo.CurrentCulture)); - break; - case DbType.Int16: - _sql.Bind_Int32(this, index, Convert.ToInt16(obj, CultureInfo.CurrentCulture)); - break; - case DbType.Int32: - _sql.Bind_Int32(this, index, Convert.ToInt32(obj, CultureInfo.CurrentCulture)); - break; - case DbType.Int64: - _sql.Bind_Int64(this, index, Convert.ToInt64(obj, CultureInfo.CurrentCulture)); - break; - case DbType.Byte: - _sql.Bind_UInt32(this, index, Convert.ToByte(obj, CultureInfo.CurrentCulture)); - break; - case DbType.UInt16: - _sql.Bind_UInt32(this, index, Convert.ToUInt16(obj, CultureInfo.CurrentCulture)); - break; - case DbType.UInt32: - _sql.Bind_UInt32(this, index, Convert.ToUInt32(obj, CultureInfo.CurrentCulture)); - break; - case DbType.UInt64: - _sql.Bind_UInt64(this, index, Convert.ToUInt64(obj, CultureInfo.CurrentCulture)); + case DbType.Boolean: + _sql.Bind_Int32(this, _flags, index, ToBoolean(obj, CultureInfo.CurrentCulture) ? 1 : 0); + break; + case DbType.SByte: + _sql.Bind_Int32(this, _flags, index, Convert.ToSByte(obj, CultureInfo.CurrentCulture)); + break; + case DbType.Int16: + _sql.Bind_Int32(this, _flags, index, Convert.ToInt16(obj, CultureInfo.CurrentCulture)); + break; + case DbType.Int32: + _sql.Bind_Int32(this, _flags, index, Convert.ToInt32(obj, CultureInfo.CurrentCulture)); + break; + case DbType.Int64: + _sql.Bind_Int64(this, _flags, index, Convert.ToInt64(obj, CultureInfo.CurrentCulture)); + break; + case DbType.Byte: + _sql.Bind_UInt32(this, _flags, index, Convert.ToByte(obj, CultureInfo.CurrentCulture)); + break; + case DbType.UInt16: + _sql.Bind_UInt32(this, _flags, index, Convert.ToUInt16(obj, CultureInfo.CurrentCulture)); + break; + case DbType.UInt32: + _sql.Bind_UInt32(this, _flags, index, Convert.ToUInt32(obj, CultureInfo.CurrentCulture)); + break; + case DbType.UInt64: + _sql.Bind_UInt64(this, _flags, index, Convert.ToUInt64(obj, CultureInfo.CurrentCulture)); break; case DbType.Single: case DbType.Double: case DbType.Currency: - //case DbType.Decimal: // Dont store decimal as double ... loses precision - _sql.Bind_Double(this, index, Convert.ToDouble(obj, CultureInfo.CurrentCulture)); + //case DbType.Decimal: // Dont store decimal as double ... loses precision + _sql.Bind_Double(this, _flags, index, Convert.ToDouble(obj, CultureInfo.CurrentCulture)); break; - case DbType.Binary: - _sql.Bind_Blob(this, index, (byte[])obj); + case DbType.Binary: + _sql.Bind_Blob(this, _flags, index, (byte[])obj); break; case DbType.Guid: - if (_command.Connection._binaryGuid == true) - _sql.Bind_Blob(this, index, ((Guid)obj).ToByteArray()); - else - _sql.Bind_Text(this, index, obj.ToString()); + if (_command.Connection._binaryGuid == true) + _sql.Bind_Blob(this, _flags, index, ((Guid)obj).ToByteArray()); + else + _sql.Bind_Text(this, _flags, index, obj.ToString()); break; - case DbType.Decimal: // Dont store decimal as double ... loses precision - _sql.Bind_Text(this, index, Convert.ToDecimal(obj, CultureInfo.CurrentCulture).ToString(CultureInfo.InvariantCulture)); + case DbType.Decimal: // Dont store decimal as double ... loses precision + _sql.Bind_Text(this, _flags, index, Convert.ToDecimal(obj, CultureInfo.CurrentCulture).ToString(CultureInfo.InvariantCulture)); break; - default: - _sql.Bind_Text(this, index, obj.ToString()); + default: + _sql.Bind_Text(this, _flags, index, obj.ToString()); break; } } internal string[] TypeDefinitions Index: System.Data.SQLite/UnsafeNativeMethods.cs ================================================================== --- System.Data.SQLite/UnsafeNativeMethods.cs +++ System.Data.SQLite/UnsafeNativeMethods.cs @@ -881,11 +881,11 @@ // Handles the unmanaged database pointer, and provides finalization support for it. internal class SQLiteConnectionHandle : CriticalHandle { public static implicit operator IntPtr(SQLiteConnectionHandle db) { - return db.handle; + return (db != null) ? db.handle : IntPtr.Zero; } public static implicit operator SQLiteConnectionHandle(IntPtr db) { return new SQLiteConnectionHandle(db); @@ -957,11 +957,11 @@ // Provides finalization support for unmanaged SQLite statements. internal class SQLiteStatementHandle : CriticalHandle { public static implicit operator IntPtr(SQLiteStatementHandle stmt) { - return stmt.handle; + return (stmt != null) ? stmt.handle : IntPtr.Zero; } public static implicit operator SQLiteStatementHandle(IntPtr stmt) { return new SQLiteStatementHandle(stmt); Index: Tests/basic.eagle ================================================================== --- Tests/basic.eagle +++ Tests/basic.eagle @@ -1002,12 +1002,12 @@ Format=False\} 0 \{True, Read Only=True\} 0 \{secret, Password=secret\} 0\ \{4096, Page Size=4096\} 0 \{1024, Max Page Count=1024\} 0 \{8192, Cache\ Size=8192\} 0 \{UnixEpoch, DateTimeFormat=UnixEpoch\} 0 \{Utc,\ DateTimeKind=Utc\} 0 \{sqlite_schema, BaseSchemaName=sqlite_schema\} 0\ \{Memory, Journal Mode=Memory\} 0 \{Serializable, Default\ -IsolationLevel=Serializable\} 0 \{False, Foreign Keys=False\} 0 \{Default,\ -Flags=Default\}$}} +IsolationLevel=Serializable\} 0 \{False, Foreign Keys=False\} 0 \{None,\ +Flags=None\}$}} ############################################################################### runTest {test data-1.17 {SQLiteConvert ToDateTime (Julian Day)} -body { set dateTime [object invoke System.Data.SQLite.SQLiteConvert ToDateTime \