Index: System.Data.SQLite/SQLiteKeyReader.cs ================================================================== --- System.Data.SQLite/SQLiteKeyReader.cs +++ System.Data.SQLite/SQLiteKeyReader.cs @@ -40,58 +40,108 @@ internal int column; } /// /// A single sub-query for a given table/database. - /// - private sealed class KeyQuery : IDisposable - { - private SQLiteCommand _command; - internal SQLiteDataReader _reader; - - internal KeyQuery(SQLiteConnection cnn, string database, string table, params string[] columns) - { - using (SQLiteCommandBuilder builder = new SQLiteCommandBuilder()) - { - _command = cnn.CreateCommand(); - for (int n = 0; n < columns.Length; n++) - { - columns[n] = builder.QuoteIdentifier(columns[n]); - } - } - _command.CommandText = String.Format(CultureInfo.InvariantCulture, "SELECT {0} FROM [{1}].[{2}] WHERE ROWID = ?", String.Join(",", columns), database, table); - _command.Parameters.AddWithValue(null, (long)0); - } - - internal bool IsValid - { - set - { - if (value != false) throw new ArgumentException(); - if (_reader != null) - { - _reader.Dispose(); - _reader = null; - } - } - } - - internal void Sync(long rowid) - { - IsValid = false; - _command.Parameters[0].Value = rowid; - _reader = _command.ExecuteReader(); - _reader.Read(); - } - - public void Dispose() - { - IsValid = false; - - if (_command != null) _command.Dispose(); - _command = null; - } + /// + private sealed class KeyQuery : IDisposable + { + private SQLiteCommand _command; + internal SQLiteDataReader _reader; + + internal KeyQuery(SQLiteConnection cnn, string database, string table, params string[] columns) + { + using (SQLiteCommandBuilder builder = new SQLiteCommandBuilder()) + { + _command = cnn.CreateCommand(); + for (int n = 0; n < columns.Length; n++) + { + columns[n] = builder.QuoteIdentifier(columns[n]); + } + } + _command.CommandText = String.Format(CultureInfo.InvariantCulture, "SELECT {0} FROM [{1}].[{2}] WHERE ROWID = ?", String.Join(",", columns), database, table); + _command.Parameters.AddWithValue(null, (long)0); + } + + internal bool IsValid + { + set + { + if (value != false) throw new ArgumentException(); + if (_reader != null) + { + _reader.Dispose(); + _reader = null; + } + } + } + + internal void Sync(long rowid) + { + IsValid = false; + _command.Parameters[0].Value = rowid; + _reader = _command.ExecuteReader(); + _reader.Read(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable Members + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable "Pattern" Members + private bool disposed; + private void CheckDisposed() /* throw */ + { +#if THROW_ON_DISPOSED + if (disposed) + throw new ObjectDisposedException(typeof(KeyQuery).Name); +#endif + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + private void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + //////////////////////////////////// + // dispose managed resources here... + //////////////////////////////////// + + IsValid = false; + + if (_command != null) _command.Dispose(); + _command = null; + } + + ////////////////////////////////////// + // release unmanaged resources here... + ////////////////////////////////////// + + disposed = true; + } + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region Destructor + ~KeyQuery() + { + Dispose(false); + } + #endregion } /// /// This function does all the nasty work at determining what keys need to be returned for /// a given statement. @@ -257,10 +307,77 @@ // CommandBehavior.KeyInfo _keyInfo = new KeyInfo[keys.Count]; keys.CopyTo(_keyInfo); } + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable Members + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable "Pattern" Members + private bool disposed; + private void CheckDisposed() /* throw */ + { +#if THROW_ON_DISPOSED + if (disposed) + throw new ObjectDisposedException(typeof(SQLiteKeyReader).Name); +#endif + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + private void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + //////////////////////////////////// + // dispose managed resources here... + //////////////////////////////////// + + _stmt = null; + + if (_keyInfo == null) return; + + for (int n = 0; n < _keyInfo.Length; n++) + { + if (_keyInfo[n].query != null) + _keyInfo[n].query.Dispose(); + } + + _keyInfo = null; + } + + ////////////////////////////////////// + // release unmanaged resources here... + ////////////////////////////////////// + + disposed = true; + } + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region Destructor + ~SQLiteKeyReader() + { + Dispose(false); + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// /// How many additional columns of keyinfo we're holding /// internal int Count { @@ -312,24 +429,10 @@ if (_keyInfo[n].query != null) _keyInfo[n].query.IsValid = false; } } - public void Dispose() - { - _stmt = null; - - if (_keyInfo == null) return; - - for (int n = 0; n < _keyInfo.Length; n++) - { - if (_keyInfo[n].query != null) - _keyInfo[n].query.Dispose(); - } - _keyInfo = null; - } - internal string GetDataTypeName(int i) { Sync(); if (_keyInfo[i].query != null) return _keyInfo[i].query._reader.GetDataTypeName(_keyInfo[i].column); else return "integer"; Index: System.Data.SQLite/SQLiteStatement.cs ================================================================== --- System.Data.SQLite/SQLiteStatement.cs +++ System.Data.SQLite/SQLiteStatement.cs @@ -86,10 +86,79 @@ _paramValues[x] = null; } } } + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable Members + /// + /// Disposes and finalizes the statement + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable "Pattern" Members + private bool disposed; + private void CheckDisposed() /* throw */ + { +#if THROW_ON_DISPOSED + if (disposed) + throw new ObjectDisposedException(typeof(SQLiteStatement).Name); +#endif + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + if (disposing) + { + //////////////////////////////////// + // dispose managed resources here... + //////////////////////////////////// + + if (_sqlite_stmt != null) + { + _sqlite_stmt.Dispose(); + _sqlite_stmt = null; + } + + _paramNames = null; + _paramValues = null; + _sql = null; + _sqlStatement = null; + } + + ////////////////////////////////////// + // release unmanaged resources here... + ////////////////////////////////////// + + disposed = true; + } + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region Destructor + ~SQLiteStatement() + { + Dispose(false); + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// /// Called by SQLiteParameterCollection, this function determines if the specified parameter name belongs to /// this statement, and if so, keeps a reference to the parameter so it can be bound later. /// /// The parameter name to map @@ -115,29 +184,10 @@ } } return false; } - #region IDisposable Members - /// - /// Disposes and finalizes the statement - /// - public void Dispose() - { - if (_sqlite_stmt != null) - { - _sqlite_stmt.Dispose(); - } - _sqlite_stmt = null; - - _paramNames = null; - _paramValues = null; - _sql = null; - _sqlStatement = null; - } - #endregion - /// /// Bind all parameters, making sure the caller didn't miss any /// internal void BindParameters() { Index: System.Data.SQLite/SQLiteTransaction.cs ================================================================== --- System.Data.SQLite/SQLiteTransaction.cs +++ System.Data.SQLite/SQLiteTransaction.cs @@ -55,17 +55,69 @@ _cnn._transactionLevel--; _cnn = null; throw; } } - } + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + #region IDisposable "Pattern" Members + private bool disposed; + private void CheckDisposed() /* throw */ + { +#if THROW_ON_DISPOSED + if (disposed) + throw new ObjectDisposedException(typeof(SQLiteTransaction).Name); +#endif + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + + /// + /// Disposes the transaction. If it is currently active, any changes are rolled back. + /// + protected override void Dispose(bool disposing) + { + try + { + if (!disposed) + { + if (disposing) + { + //////////////////////////////////// + // dispose managed resources here... + //////////////////////////////////// + + if (IsValid(false)) + { + IssueRollback(); + } + } + + ////////////////////////////////////// + // release unmanaged resources here... + ////////////////////////////////////// + + disposed = true; + } + } + finally + { + base.Dispose(disposing); + } + } + #endregion + + /////////////////////////////////////////////////////////////////////////////////////////////// /// /// Commits the current transaction. /// public override void Commit() - { + { + CheckDisposed(); IsValid(true); if (_cnn._transactionLevel - 1 == 0) { using (SQLiteCommand cmd = _cnn.CreateCommand()) @@ -80,50 +132,36 @@ /// /// Returns the underlying connection to which this transaction applies. /// public new SQLiteConnection Connection - { - get { return _cnn; } + { + get { CheckDisposed(); return _cnn; } } /// /// Forwards to the local Connection property /// protected override DbConnection DbConnection - { + { get { return Connection; } } - /// - /// Disposes the transaction. If it is currently active, any changes are rolled back. - /// - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (IsValid(false)) - { - IssueRollback(); - } - } - base.Dispose(disposing); - } - /// /// Gets the isolation level of the transaction. SQLite only supports Serializable transactions. /// public override IsolationLevel IsolationLevel - { - get { return _level; } + { + get { CheckDisposed(); return _level; } } /// /// Rolls back the active transaction. /// public override void Rollback() - { + { + CheckDisposed(); IsValid(true); IssueRollback(); } internal void IssueRollback() Index: System.Data.SQLite/SR.Designer.cs ================================================================== --- System.Data.SQLite/SR.Designer.cs +++ System.Data.SQLite/SR.Designer.cs @@ -1,5 +1,12 @@ +/******************************************************** + * ADO.NET 2.0 Data Provider for SQLite Version 3.X + * Written by Robert Simpson (robert@blackcastlesoft.com) + * + * Released to the public domain, use at your own risk! + ********************************************************/ + //------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.1 //