Index: System.Data.SQLite/SQLiteCommand.cs ================================================================== --- System.Data.SQLite/SQLiteCommand.cs +++ System.Data.SQLite/SQLiteCommand.cs @@ -1,9 +1,9 @@ /******************************************************** * 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! ********************************************************/ namespace System.Data.SQLite { @@ -88,11 +88,11 @@ /// /// Initializes the command with the given command text /// /// The SQL command text - public SQLiteCommand(string commandText) + public SQLiteCommand(string commandText) : this(commandText, null, null) { } /// @@ -108,11 +108,11 @@ /// /// Initializes the command and associates it with the specified connection. /// /// The connection to associate with the command - public SQLiteCommand(SQLiteConnection connection) + public SQLiteCommand(SQLiteConnection connection) : this(null, connection, null) { } private SQLiteCommand(SQLiteCommand source) : this(source.CommandText, source.Connection, source.Transaction) @@ -304,32 +304,40 @@ _statementList = null; } /////////////////////////////////////////////////////////////////////////////////////////////// - /// - /// Clears and destroys all statements currently prepared - /// - internal void ClearCommands() + private void ClearDataReader() { if (_activeReader != null) { SQLiteDataReader reader = null; + try { reader = _activeReader.Target as SQLiteDataReader; } catch(InvalidOperationException) { + // do nothing. } if (reader != null) - reader.Close(); + reader.Close(); /* Dispose */ _activeReader = null; } + } + /////////////////////////////////////////////////////////////////////////////////////////////// + + /// + /// Clears and destroys all statements currently prepared + /// + internal void ClearCommands() + { + ClearDataReader(); DisposeStatements(); _parameterCollection.Unbind(); } @@ -879,11 +887,11 @@ } /// /// Called by the SQLiteDataReader when the data reader is closed. /// - internal void ClearDataReader() + internal void ResetDataReader() { _activeReader = null; } /// @@ -948,10 +956,77 @@ if (reader.Read()) return reader[0]; } return null; } + + /// + /// This method resets all the prepared statements held by this instance + /// back to their initial states, ready to be re-executed. + /// + public void Reset() + { + CheckDisposed(); + SQLiteConnection.Check(_cnn); + + Reset(true, false); + } + + /// + /// This method resets all the prepared statements held by this instance + /// back to their initial states, ready to be re-executed. + /// + /// + /// Non-zero if the parameter bindings should be cleared as well. + /// + /// + /// If this is zero, a may be thrown for + /// any unsuccessful return codes from the native library; otherwise, a + /// will only be thrown if the connection + /// or its state is invalid. + /// + public void Reset( + bool clearBindings, + bool ignoreErrors + ) + { + CheckDisposed(); + SQLiteConnection.Check(_cnn); + + if (clearBindings && (_parameterCollection != null)) + _parameterCollection.Unbind(); + + ClearDataReader(); + + if (_statementList == null) + return; + + SQLiteBase sqlBase = _cnn._sql; + SQLiteErrorCode rc; + + foreach (SQLiteStatement item in _statementList) + { + if (item == null) + continue; + + SQLiteStatementHandle stmt = item._sqlite_stmt; + + if (stmt == null) + continue; + + rc = sqlBase.Reset(item); + + if ((rc == SQLiteErrorCode.Ok) && clearBindings && + (SQLite3.SQLiteVersionNumber >= 3003007)) + { + rc = UnsafeNativeMethods.sqlite3_clear_bindings(stmt); + } + + if (!ignoreErrors && (rc != SQLiteErrorCode.Ok)) + throw new SQLiteException(rc, sqlBase.GetLastError()); + } + } /// /// Does nothing. Commands are prepared as they are executed the first time, and kept in prepared state afterwards. /// public override void Prepare() Index: System.Data.SQLite/SQLiteDataReader.cs ================================================================== --- System.Data.SQLite/SQLiteDataReader.cs +++ System.Data.SQLite/SQLiteDataReader.cs @@ -222,11 +222,11 @@ } catch(SQLiteException) { } } - _command.ClearDataReader(); + _command.ResetDataReader(); } finally { // If the datareader's behavior includes closing the connection, then do so here. if ((_commandBehavior & CommandBehavior.CloseConnection) != 0 && _command.Connection != null) Index: System.Data.SQLite/UnsafeNativeMethods.cs ================================================================== --- System.Data.SQLite/UnsafeNativeMethods.cs +++ System.Data.SQLite/UnsafeNativeMethods.cs @@ -1861,10 +1861,17 @@ #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_busy_timeout(IntPtr db, int ms); +#if !PLATFORM_COMPACTFRAMEWORK + [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] +#else + [DllImport(SQLITE_DLL)] +#endif + internal static extern SQLiteErrorCode sqlite3_clear_bindings(IntPtr stmt); + #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif Index: Tests/basic.eagle ================================================================== --- Tests/basic.eagle +++ Tests/basic.eagle @@ -3852,10 +3852,62 @@ rename getMyFuncArgs "" } -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\ System.Data.SQLite} -match regexp -result {^0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 \{1\ 2 3 A a M m Z z\} True 1 True 1 True 1 True 1 True 1 True 1 True 1 True 1\ \{(?:-)?\d+ (?:-)?\d+\}$}} + +############################################################################### + +runTest {test data-1.75 {SQLiteCommand.Reset method} -setup { + setupDb [set fileName data-1.75.db] +} -body { + set connection [getDbConnection] + + set result [list] + + sql execute $db { + CREATE TABLE t1(x); + INSERT INTO t1 (x) VALUES(1); + INSERT INTO t1 (x) VALUES(2); + INSERT INTO t1 (x) VALUES(3); + INSERT INTO t1 (x) VALUES(4); + } + + set command [$connection -alias CreateCommand] + set parameter [$command -alias CreateParameter] + + $parameter ParameterName param1 + $parameter DbType Int32 + $parameter Value 4 + + $command CommandText "SELECT x FROM t1 WHERE x < ? ORDER BY x;" + $command Parameters.Add $parameter + + set dataReader(1) [$command -alias ExecuteReader] + + $dataReader(1) Read; lappend result [$dataReader(1) Item x] + $dataReader(1) Read; lappend result [$dataReader(1) Item x] + + $command Reset; set dataReader(2) [$command -alias ExecuteReader] + $dataReader(2) Read; lappend result [$dataReader(2) Item x] + $dataReader(2) Read; lappend result [$dataReader(2) Item x] + + $command Reset; set dataReader(3) [$command -alias ExecuteReader] + $dataReader(3) Read; lappend result [$dataReader(3) Item x] + $dataReader(3) Read; lappend result [$dataReader(3) Item x] + + set result +} -cleanup { + unset -nocomplain dataReader parameter command connection + + freeDbConnection + + cleanupDb $fileName + + unset -nocomplain result db fileName +} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\ +System.Data.SQLite} -result {1 2 1 2 1 2}} ############################################################################### reportSQLiteResources $test_channel