Index: System.Data.SQLite/SQLite3.cs ================================================================== --- System.Data.SQLite/SQLite3.cs +++ System.Data.SQLite/SQLite3.cs @@ -124,10 +124,15 @@ { if (db != IntPtr.Zero) { _sql = new SQLiteConnectionHandle(db, ownHandle); _fileName = fileName; + + SQLiteConnection.OnChanged(null, new ConnectionEventArgs( + SQLiteConnectionEventType.NewCriticalHandle, null, null, + null, null, _sql, fileName, new object[] { fmt, kind, + fmtString, db, fileName, ownHandle })); } } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -535,10 +540,15 @@ if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null); _sql = new SQLiteConnectionHandle(db, true); } lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ } + + SQLiteConnection.OnChanged(null, new ConnectionEventArgs( + SQLiteConnectionEventType.NewCriticalHandle, null, null, + null, null, _sql, strFilename, new object[] { strFilename, + connectionFlags, openFlags, maxPoolSize, usePool })); } // Bind functions to this connection. If any previous functions of the same name // were already bound, then the new bindings replace the old. if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions) @@ -741,11 +751,22 @@ #if !NET_COMPACT_20 && TRACE_STATEMENT Trace.WriteLine(String.Format("Prepare ({0}): {1}", n, stmt)); #endif if ((n == SQLiteErrorCode.Ok) && (stmt != IntPtr.Zero)) + { + if (statementHandle != null) statementHandle.Dispose(); statementHandle = new SQLiteStatementHandle(_sql, stmt); + } + } + + if (statementHandle != null) + { + SQLiteConnection.OnChanged(null, new ConnectionEventArgs( + SQLiteConnectionEventType.NewCriticalHandle, null, null, + null, null, statementHandle, strSql, new object[] { cnn, + strSql, previous, timeoutMS })); } if (n == SQLiteErrorCode.Schema) retries++; else if (n == SQLiteErrorCode.Error) @@ -2105,10 +2126,15 @@ throw new SQLiteException("failed to initialize backup"); } backupHandle = new SQLiteBackupHandle(destHandle, backup); } + + SQLiteConnection.OnChanged(null, new ConnectionEventArgs( + SQLiteConnectionEventType.NewCriticalHandle, null, null, + null, null, backupHandle, null, new object[] { destCnn, + destName, sourceName })); return new SQLiteBackup( this, backupHandle, destHandle, zDestName, sourceHandle, zSourceName); } Index: System.Data.SQLite/SQLite3_UTF16.cs ================================================================== --- System.Data.SQLite/SQLite3_UTF16.cs +++ System.Data.SQLite/SQLite3_UTF16.cs @@ -194,10 +194,15 @@ if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null); _sql = new SQLiteConnectionHandle(db, true); } lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ } + + SQLiteConnection.OnChanged(null, new ConnectionEventArgs( + SQLiteConnectionEventType.NewCriticalHandle, null, null, + null, null, _sql, strFilename, new object[] { strFilename, + connectionFlags, openFlags, maxPoolSize, usePool })); } // Bind functions to this connection. If any previous functions of the same name // were already bound, then the new bindings replace the old. if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions) Index: System.Data.SQLite/SQLiteCommand.cs ================================================================== --- System.Data.SQLite/SQLiteCommand.cs +++ System.Data.SQLite/SQLiteCommand.cs @@ -149,11 +149,12 @@ if (transaction != null) Transaction = transaction; SQLiteConnection.OnChanged(connection, new ConnectionEventArgs( - SQLiteConnectionEventType.NewCommand, null, transaction, this, null, null)); + SQLiteConnectionEventType.NewCommand, null, transaction, this, + null, null, null, null)); } /////////////////////////////////////////////////////////////////////////////////////////////// [Conditional("CHECK_STATE")] Index: System.Data.SQLite/SQLiteConnection.cs ================================================================== --- System.Data.SQLite/SQLiteConnection.cs +++ System.Data.SQLite/SQLiteConnection.cs @@ -43,10 +43,20 @@ /// /// The command associated with this event, if any. /// public readonly IDbCommand Command; + /// + /// The data reader associated with this event, if any. + /// + public readonly IDataReader DataReader; + + /// + /// The critical handle associated with this event, if any. + /// + public readonly CriticalHandle CriticalHandle; + /// /// Command or message text associated with this event, if any. /// public readonly string Text; @@ -61,25 +71,31 @@ /// The type of event being raised. /// The base associated /// with this event, if any. /// The transaction associated with this event, if any. /// The command associated with this event, if any. + /// The data reader associated with this event, if any. + /// The critical handle associated with this event, if any. /// The command or message text, if any. /// The extra data, if any. internal ConnectionEventArgs( SQLiteConnectionEventType eventType, StateChangeEventArgs eventArgs, IDbTransaction transaction, IDbCommand command, + IDataReader dataReader, + CriticalHandle criticalHandle, string text, object data ) { EventType = eventType; EventArgs = eventArgs; Transaction = transaction; Command = command; + DataReader = dataReader; + CriticalHandle = criticalHandle; Text = text; Data = data; } } @@ -489,10 +505,12 @@ // do nothing. } /// /// Initializes the connection with a pre-existing native connection handle. + /// This constructor overload is intended to be used only by the private + /// method. /// /// /// The native connection handle to use. /// /// @@ -615,25 +633,24 @@ /// /// Raises the event. /// /// - /// The connection associated with this event. + /// The connection associated with this event. If this parameter is not + /// null and the specified connection cannot raise events, then the + /// registered event handlers will not be invoked. /// /// /// A that contains the event data. /// internal static void OnChanged( SQLiteConnection connection, ConnectionEventArgs e ) { - if (connection == null) - return; - #if !PLATFORM_COMPACTFRAMEWORK - if (!connection.CanRaiseEvents) + if ((connection != null) && !connection.CanRaiseEvents) return; #endif SQLiteConnectionEventHandler handlers; @@ -710,12 +727,30 @@ /// public static object CreateHandle( IntPtr nativeHandle ) { - if (nativeHandle == IntPtr.Zero) return null; - return new SQLiteConnectionHandle(nativeHandle, true); + SQLiteConnectionHandle result; + + try + { + // do nothing. + } + finally /* NOTE: Thread.Abort() protection. */ + { + result = (nativeHandle != IntPtr.Zero) ? + new SQLiteConnectionHandle(nativeHandle, true) : null; + } + + if (result != null) + { + SQLiteConnection.OnChanged(null, new ConnectionEventArgs( + SQLiteConnectionEventType.NewCriticalHandle, null, null, + null, null, result, null, new object[] { nativeHandle })); + } + + return result; } /////////////////////////////////////////////////////////////////////////////////////////////// #region Backup API Members @@ -1135,11 +1170,12 @@ SQLiteTransaction transaction = new SQLiteTransaction(this, isolationLevel != IsolationLevel.Serializable); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.NewTransaction, null, transaction, null, null, null)); + SQLiteConnectionEventType.NewTransaction, null, transaction, + null, null, null, null, null)); return transaction; } /// @@ -1150,11 +1186,12 @@ public override void ChangeDatabase(string databaseName) { CheckDisposed(); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.ChangeDatabase, null, null, null, databaseName, null)); + SQLiteConnectionEventType.ChangeDatabase, null, null, null, null, + null, databaseName, null)); throw new NotImplementedException(); // NOTE: For legacy compatibility. } /// @@ -1163,11 +1200,12 @@ public override void Close() { CheckDisposed(); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.Closing, null, null, null, null, null)); + SQLiteConnectionEventType.Closing, null, null, null, null, null, + null, null)); if (_sql != null) { #if !PLATFORM_COMPACTFRAMEWORK if (_enlistment != null) @@ -1199,11 +1237,12 @@ StateChangeEventArgs eventArgs = null; OnStateChange(ConnectionState.Closed, ref eventArgs); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.Closed, eventArgs, null, null, null, null)); + SQLiteConnectionEventType.Closed, eventArgs, null, null, null, + null, null, null)); } /// /// Returns the number of pool entries for the file name associated with this connection. /// @@ -1661,11 +1700,12 @@ throw new ArgumentNullException("Unable to enlist in transaction, it is null"); _enlistment = new SQLiteEnlistment(this, transaction); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.EnlistTransaction, null, null, null, null, _enlistment)); + SQLiteConnectionEventType.EnlistTransaction, null, null, null, null, + null, null, new object[] { _enlistment })); } #endif /// /// Looks for a key in the array of key/values of the parameter string. If not found, return the specified default value @@ -1950,11 +1990,12 @@ public override void Open() { CheckDisposed(); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.Opening, null, null, null, null, null)); + SQLiteConnectionEventType.Opening, null, null, null, null, null, + null, null)); if (_connectionState != ConnectionState.Closed) throw new InvalidOperationException(); Close(); @@ -1961,11 +2002,12 @@ SortedList opts = ParseConnectionString( _connectionString, _parseViaFramework); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.ConnectionString, null, null, null, _connectionString, opts)); + SQLiteConnectionEventType.ConnectionString, null, null, null, null, + null, _connectionString, new object[] { opts })); object enumValue; enumValue = TryParseEnum(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", DefaultFlags.ToString()), true); _flags = (enumValue is SQLiteConnectionFlags) ? (SQLiteConnectionFlags)enumValue : DefaultFlags; @@ -2191,11 +2233,12 @@ StateChangeEventArgs eventArgs = null; OnStateChange(ConnectionState.Open, ref eventArgs); OnChanged(this, new ConnectionEventArgs( - SQLiteConnectionEventType.Opened, eventArgs, null, null, null, null)); + SQLiteConnectionEventType.Opened, eventArgs, null, null, null, + null, null, null)); } catch { _connectionState = oldstate; throw; Index: System.Data.SQLite/SQLiteConvert.cs ================================================================== --- System.Data.SQLite/SQLiteConvert.cs +++ System.Data.SQLite/SQLiteConvert.cs @@ -1301,33 +1301,46 @@ /// /// A data reader was created using the connection. /// NewDataReader = 8, + /// + /// An instance of a derived class has + /// been created to wrap a native resource. + /// + NewCriticalHandle = 9, + /// /// The connection is being closed. /// - Closing = 9, + Closing = 10, /// /// The connection was closed. /// - Closed = 10 + Closed = 11 } /// - /// This implementation of SQLite for ADO.NET can process date/time fields in databases in only one of three formats. Ticks, ISO8601 - /// and JulianDay. + /// This implementation of SQLite for ADO.NET can process date/time fields in + /// databases in one of six formats. /// /// - /// ISO8601 is more compatible, readable, fully-processable, but less accurate as it doesn't provide time down to fractions of a second. - /// JulianDay is the numeric format the SQLite uses internally and is arguably the most compatible with 3rd party tools. It is - /// not readable as text without post-processing. - /// Ticks less compatible with 3rd party tools that query the database, and renders the DateTime field unreadable as text without post-processing. + /// ISO8601 format is more compatible, readable, fully-processable, but less + /// accurate as it does not provide time down to fractions of a second. + /// JulianDay is the numeric format the SQLite uses internally and is arguably + /// the most compatible with 3rd party tools. It is not readable as text + /// without post-processing. Ticks less compatible with 3rd party tools that + /// query the database, and renders the DateTime field unreadable as text + /// without post-processing. UnixEpoch is more compatible with Unix systems. + /// InvariantCulture allows the configured format for the invariant culture + /// format to be used and is human readable. CurrentCulture allows the + /// configured format for the current culture to be used and is also human + /// readable. /// - /// The preferred order of choosing a datetime format is JulianDay, ISO8601, and then Ticks. Ticks is mainly present for legacy - /// code support. + /// The preferred order of choosing a DateTime format is JulianDay, ISO8601, + /// and then Ticks. Ticks is mainly present for legacy code support. /// public enum SQLiteDateFormats { /// /// Use the value of DateTime.Ticks. This value is not recommended and is not well supported with LINQ. Index: System.Data.SQLite/SQLiteDataReader.cs ================================================================== --- System.Data.SQLite/SQLiteDataReader.cs +++ System.Data.SQLite/SQLiteDataReader.cs @@ -106,11 +106,11 @@ if (_command != null) { SQLiteConnection.OnChanged(_command.Connection, new ConnectionEventArgs(SQLiteConnectionEventType.NewDataReader, - null, null, _command, null, new object[] { this, behave })); + null, null, _command, this, null, null, new object[] { behave })); NextResult(); } }