X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Data%2FSystem.Data.SqlClient%2FSqlCommand.cs;h=b0962359876ee29436e75ccbf9974bb4459915db;hb=cb091188403237aa3eb87f39a09f00f642750cc2;hp=95520667825112728769ae613837d94c7373c249;hpb=9869ae24b88761ab261c4311e24f7383b4af3f02;p=mono.git diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs index 95520667825..b0962359876 100644 --- a/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs +++ b/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs @@ -38,27 +38,33 @@ using Mono.Data.Tds; using Mono.Data.Tds.Protocol; using System; +using System.IO; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.Data; using System.Data.Common; +#if NET_2_0 +using System.Data.Sql; +#endif using System.Runtime.InteropServices; using System.Text; using System.Xml; namespace System.Data.SqlClient { [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.SqlCommandDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")] - [ToolboxItemAttribute ("System.Drawing.Design.ToolboxItem, "+ Consts.AssemblySystem_Drawing)] + [ToolboxItemAttribute ("System.Drawing.Design.ToolboxItem, "+ Consts.AssemblySystem_Drawing)] #if NET_2_0 + [DefaultEventAttribute ("RecordsAffected")] public sealed class SqlCommand : DbCommand, IDbCommand, ICloneable #else - public sealed class SqlCommand : Component, IDbCommand, ICloneable + public sealed class SqlCommand : Component, IDbCommand, ICloneable #endif // NET_2_0 { #region Fields - bool disposed = false; + const int DEFAULT_COMMAND_TIMEOUT = 30; + int commandTimeout; bool designTimeVisible; string commandText; @@ -68,7 +74,12 @@ namespace System.Data.SqlClient { UpdateRowSource updatedRowSource; CommandBehavior behavior = CommandBehavior.Default; SqlParameterCollection parameters; - string preparedStatement = null; + string preparedStatement; +#if NET_2_0 + bool disposed; + SqlNotificationRequest notification; + bool notificationAutoEnlist; +#endif #endregion // Fields @@ -79,26 +90,29 @@ namespace System.Data.SqlClient { { } - public SqlCommand (string commandText) - : this (commandText, null, null) + public SqlCommand (string cmdText) + : this (cmdText, null, null) { } - public SqlCommand (string commandText, SqlConnection connection) - : this (commandText, connection, null) + public SqlCommand (string cmdText, SqlConnection connection) + : this (cmdText, connection, null) { } - public SqlCommand (string commandText, SqlConnection connection, SqlTransaction transaction) + public SqlCommand (string cmdText, SqlConnection connection, SqlTransaction transaction) { - this.commandText = commandText; + this.commandText = cmdText; this.connection = connection; this.transaction = transaction; this.commandType = CommandType.Text; this.updatedRowSource = UpdateRowSource.Both; - this.designTimeVisible = false; - this.commandTimeout = 30; + this.commandTimeout = DEFAULT_COMMAND_TIMEOUT; +#if NET_2_0 + notificationAutoEnlist = true; +#endif + designTimeVisible = true; parameters = new SqlParameterCollection (this); } @@ -113,8 +127,9 @@ namespace System.Data.SqlClient { this.commandTimeout = commandTimeout; this.parameters = new SqlParameterCollection(this); for (int i = 0;i < parameters.Count;i++) - this.parameters.Add(((ICloneable)parameters[i]).Clone()); + this.parameters.Add(((ICloneable)parameters[i]).Clone()); } + #endregion // Constructors #region Properties @@ -123,135 +138,151 @@ namespace System.Data.SqlClient { get { return behavior; } } - [DataCategory ("Data")] #if !NET_2_0 [DataSysDescription ("Command text to execute.")] #endif [DefaultValue ("")] [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )] [RefreshProperties (RefreshProperties.All)] - public + public #if NET_2_0 - override + override #endif //NET_2_0 - string CommandText { - get { return commandText; } - set { + string CommandText { + get { + if (commandText == null) + return string.Empty; + return commandText; + } + set { if (value != commandText && preparedStatement != null) Unprepare (); - commandText = value; + commandText = value; } } #if !NET_2_0 [DataSysDescription ("Time to wait for command to execute.")] + [DefaultValue (DEFAULT_COMMAND_TIMEOUT)] #endif - [DefaultValue (30)] - public + public #if NET_2_0 - override + override #endif //NET_2_0 - int CommandTimeout { - get { return commandTimeout; } + int CommandTimeout { + get { return commandTimeout; } set { if (value < 0) +#if NET_2_0 + throw new ArgumentException ("The property value assigned is less than 0.", + "CommandTimeout"); +#else throw new ArgumentException ("The property value assigned is less than 0."); +#endif commandTimeout = value; } } - [DataCategory ("Data")] #if !NET_2_0 [DataSysDescription ("How to interpret the CommandText.")] #endif [DefaultValue (CommandType.Text)] [RefreshProperties (RefreshProperties.All)] - public + public #if NET_2_0 - override + override #endif //NET_2_0 - CommandType CommandType { + CommandType CommandType { get { return commandType; } set { if (value == CommandType.TableDirect) +#if NET_2_0 + throw new ArgumentOutOfRangeException ("CommandType.TableDirect is not supported " + + "by the Mono SqlClient Data Provider."); +#else throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono SqlClient Data Provider."); +#endif - if (!Enum.IsDefined (typeof (CommandType), value)) - throw ExceptionHelper.InvalidEnumValueException ("CommandType", value); + ExceptionHelper.CheckEnumValue (typeof (CommandType), value); commandType = value; } } - [DataCategory ("Behavior")] [DefaultValue (null)] #if !NET_2_0 [DataSysDescription ("Connection used by the command.")] #endif [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )] - public + public #if NET_2_0 - new + new #endif //NET_2_0 - SqlConnection Connection { + SqlConnection Connection { get { return connection; } - set { - if (transaction != null && connection.Transaction != null && connection.Transaction.IsOpen) - throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress."); - transaction = null; - connection = value; + set + { +#if ONLY_1_1 + if (connection != null && connection.DataReader != null) + throw new InvalidOperationException ("The connection is busy fetching data."); +#endif + connection = value; } } [Browsable (false)] [DefaultValue (true)] [DesignOnly (true)] - public #if NET_2_0 - override + [EditorBrowsable (EditorBrowsableState.Never)] +#endif + public +#if NET_2_0 + override #endif //NET_2_0 - bool DesignTimeVisible { + bool DesignTimeVisible { get { return designTimeVisible; } set { designTimeVisible = value; } } - [DataCategory ("Data")] #if !NET_2_0 [DataSysDescription ("The parameters collection.")] #endif [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] - public + public #if NET_2_0 - new + new #endif //NET_2_0 - SqlParameterCollection Parameters { + SqlParameterCollection Parameters { get { return parameters; } } - internal ITds Tds { + internal Tds Tds { get { return Connection.Tds; } } +#if !NET_2_0 IDbConnection IDbCommand.Connection { get { return Connection; } set { - if (!(value is SqlConnection)) + if (!(value == null || value is SqlConnection)) throw new InvalidCastException ("The value was not a valid SqlConnection."); Connection = (SqlConnection) value; } } - IDataParameterCollection IDbCommand.Parameters { + IDataParameterCollection IDbCommand.Parameters { get { return Parameters; } } IDbTransaction IDbCommand.Transaction { get { return Transaction; } - set { - if (!(value is SqlTransaction)) + set { + if (!(value == null || value is SqlTransaction)) throw new ArgumentException (); Transaction = (SqlTransaction) value; } } +#endif [Browsable (false)] #if !NET_2_0 @@ -259,72 +290,179 @@ namespace System.Data.SqlClient { #endif [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public new SqlTransaction Transaction { - get { return transaction; } - set { transaction = value; } - } + get { + if (transaction != null && !transaction.IsOpen) + transaction = null; + return transaction; + } + set + { +#if ONLY_1_1 + if (connection != null && connection.DataReader != null) + throw new InvalidOperationException ("The connection is busy fetching data."); +#endif + transaction = value; + } + } - [DataCategory ("Behavior")] #if !NET_2_0 [DataSysDescription ("When used by a DataAdapter.Update, how command results are applied to the current DataRow.")] #endif [DefaultValue (UpdateRowSource.Both)] - public + public #if NET_2_0 - override + override #endif // NET_2_0 - UpdateRowSource UpdatedRowSource { + UpdateRowSource UpdatedRowSource { get { return updatedRowSource; } - set { - if (!Enum.IsDefined (typeof (UpdateRowSource), value)) - throw ExceptionHelper.InvalidEnumValueException ("UpdateRowSource", value); + set { + ExceptionHelper.CheckEnumValue (typeof (UpdateRowSource), value); updatedRowSource = value; } } +#if NET_2_0 + [Browsable (false)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public SqlNotificationRequest Notification { + get { return notification; } + set { notification = value; } + } + + [DefaultValue (true)] + public bool NotificationAutoEnlist { + get { return notificationAutoEnlist; } + set { notificationAutoEnlist = value; } + } +#endif #endregion // Fields #region Methods - public + public #if NET_2_0 - override + override #endif // NET_2_0 - void Cancel () + void Cancel () { if (Connection == null || Connection.Tds == null) return; Connection.Tds.Cancel (); } - internal void CloseDataReader (bool moreResults) +#if NET_2_0 + public SqlCommand Clone () { - Connection.DataReader = null; + return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout, parameters); + } +#endif // NET_2_0 - if ((behavior & CommandBehavior.CloseConnection) != 0) - Connection.Close (); + internal void CloseDataReader () + { + if (Connection != null) { + Connection.DataReader = null; + + if ((behavior & CommandBehavior.CloseConnection) != 0) + Connection.Close (); + + if (Tds != null) + Tds.SequentialAccess = false; + } // Reset the behavior behavior = CommandBehavior.Default; - Tds.SequentialAccess = false; } - public new SqlParameter CreateParameter () + public new SqlParameter CreateParameter () { return new SqlParameter (); } + private string EscapeProcName (string name, bool schema) + { + string procName; + string tmpProcName = name.Trim (); + int procNameLen = tmpProcName.Length; + char[] brkts = new char [] {'[', ']'}; + bool foundMatching = false; + int start = 0, count = procNameLen; + int sindex = -1, eindex = -1; + + // We try to match most of the "brackets" combination here, however + // there could be other combinations that may generate a different type + // of exception in MS.NET + + if (procNameLen > 1) { + if ((sindex = tmpProcName.IndexOf ('[')) <= 0) + foundMatching = true; + else + foundMatching = false; + + if (foundMatching == true && sindex > -1) { + eindex = tmpProcName.IndexOf (']'); + if (sindex > eindex && eindex != -1) { + foundMatching = false; + } else if (eindex == procNameLen-1) { + if (tmpProcName.IndexOfAny (brkts, 1, procNameLen-2) != -1) { + foundMatching = false; + } else { + start = 1; + count = procNameLen - 2; + } + } else if (eindex == -1 && schema) { + foundMatching = true; + } else { + foundMatching = false; + } + } + + if (foundMatching) + procName = tmpProcName.Substring (start, count); + else + throw new ArgumentException (String.Format ("SqlCommand.CommandText property value is an invalid multipart name {0}, incorrect usage of quotes", CommandText)); + } else { + procName = tmpProcName; + } + + return procName; + } internal void DeriveParameters () { if (commandType != CommandType.StoredProcedure) throw new InvalidOperationException (String.Format ("SqlCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType)); - ValidateCommand ("DeriveParameters"); - + ValidateCommand ("DeriveParameters", false); + + string procName = CommandText; + string schemaName = String.Empty; + int dotPosition = procName.LastIndexOf ('.'); + + // Procedure name can be: [database].[user].[procname] + if (dotPosition >= 0) { + schemaName = procName.Substring (0, dotPosition); + procName = procName.Substring (dotPosition + 1); + if ((dotPosition = schemaName.LastIndexOf ('.')) >= 0) + schemaName = schemaName.Substring (dotPosition + 1); + } + + procName = EscapeProcName (procName, false); + schemaName = EscapeProcName (schemaName, true); + SqlParameterCollection localParameters = new SqlParameterCollection (this); - localParameters.Add ("@procedure_name", SqlDbType.NVarChar, commandText.Length).Value = commandText; - + localParameters.Add ("@procedure_name", SqlDbType.NVarChar, procName.Length).Value = procName; + if (schemaName.Length > 0) + localParameters.Add ("@procedure_schema", SqlDbType.NVarChar, schemaName.Length).Value = schemaName; + string sql = "sp_procedure_params_rowset"; - Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true); + try { + Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true); + } catch (TdsTimeoutException ex) { + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } SqlDataReader reader = new SqlDataReader (this); parameters.Clear (); @@ -334,14 +472,21 @@ namespace System.Data.SqlClient { reader.GetValues (dbValues); parameters.Add (new SqlParameter (dbValues)); } - reader.Close (); + reader.Close (); + if (parameters.Count == 0) + throw new InvalidOperationException ("Stored procedure '" + procName + "' does not exist."); } - private void Execute (CommandBehavior behavior, bool wantResults) + private void Execute (bool wantResults) { - Connection.Tds.RecordsAffected = -1; + int index = 0; + Connection.Tds.RecordsAffected = -1; TdsMetaParameterCollection parms = Parameters.MetaParameters; + foreach (TdsMetaParameter param in parms) { + param.Validate (index++); + } + if (preparedStatement == null) { bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0); bool keyInfo = ((behavior & CommandBehavior.KeyInfo) > 0); @@ -359,40 +504,74 @@ namespace System.Data.SqlClient { sql1.Append ("SET FMTONLY ON;"); sql2.Append ("SET FMTONLY OFF;"); } - + switch (CommandType) { case CommandType.StoredProcedure: - if (keyInfo || schemaOnly) - Connection.Tds.Execute (sql1.ToString ()); - Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults); - if (keyInfo || schemaOnly) - Connection.Tds.Execute (sql2.ToString ()); + try { + if (keyInfo || schemaOnly) + Connection.Tds.Execute (sql1.ToString ()); + Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults); + if (keyInfo || schemaOnly) + Connection.Tds.Execute (sql2.ToString ()); + } catch (TdsTimeoutException ex) { + // If it is a timeout exception there can be many reasons: + // 1) Network is down/server is down/not reachable + // 2) Somebody has an exclusive lock on Table/DB + // In any of these cases, don't close the connection. Let the user do it + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } break; case CommandType.Text: - string sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ()); - Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults); + string sql; + if (sql2.Length > 0) { + sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ()); + } else { + sql = String.Format ("{0}{1}", sql1.ToString (), CommandText); + } + try { + Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults); + } catch (TdsTimeoutException ex) { + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } break; } } - else - Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults); + else { + try { + Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults); + } catch (TdsTimeoutException ex) { + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } + } } - public + public #if NET_2_0 - override + override #endif // NET_2_0 - int ExecuteNonQuery () + int ExecuteNonQuery () { - ValidateCommand ("ExecuteNonQuery"); + ValidateCommand ("ExecuteNonQuery", false); int result = 0; - behavior = CommandBehavior.Default; + behavior = CommandBehavior.Default; try { - Execute (CommandBehavior.Default, false); + Execute (false); result = Connection.Tds.RecordsAffected; - } - catch (TdsTimeoutException e) { + } catch (TdsTimeoutException e) { + Connection.Tds.Reset (); throw SqlException.FromTdsInternalException ((TdsInternalException) e); } @@ -407,63 +586,69 @@ namespace System.Data.SqlClient { public new SqlDataReader ExecuteReader (CommandBehavior behavior) { - ValidateCommand ("ExecuteReader"); + ValidateCommand ("ExecuteReader", false); + if ((behavior & CommandBehavior.SingleRow) != 0) + behavior |= CommandBehavior.SingleResult; + this.behavior = behavior; + if ((behavior & CommandBehavior.SequentialAccess) != 0) + Tds.SequentialAccess = true; try { - this.behavior = behavior; - if ((behavior & CommandBehavior.SequentialAccess) != 0) - Tds.SequentialAccess = true; - Execute (behavior, true); - Connection.DataReader = new SqlDataReader (this); + Execute (true); + Connection.DataReader = new SqlDataReader (this); + return Connection.DataReader; + } catch { + if ((behavior & CommandBehavior.CloseConnection) != 0) + Connection.Close (); + throw; } - catch (TdsTimeoutException e) { - // if behavior is closeconnection, even if it throws exception - // the connection has to be closed. - if ((behavior & CommandBehavior.CloseConnection) != 0) - Connection.Close (); - throw SqlException.FromTdsInternalException ((TdsInternalException) e); - } catch (SqlException) { - // if behavior is closeconnection, even if it throws exception - // the connection has to be closed. - if ((behavior & CommandBehavior.CloseConnection) != 0) - Connection.Close (); - - throw; - } - - return Connection.DataReader; } - public + public #if NET_2_0 - override + override #endif // NET_2_0 - object ExecuteScalar () + object ExecuteScalar () { - ValidateCommand ("ExecuteScalar"); - behavior = CommandBehavior.Default; try { - Execute (CommandBehavior.Default, true); - } - catch (TdsTimeoutException e) { - throw SqlException.FromTdsInternalException ((TdsInternalException) e); - } + object result = null; +#if NET_2_0 + ValidateCommand ("ExecuteScalar", false); +#else + ValidateCommand ("ExecuteReader", false); +#endif + behavior = CommandBehavior.Default; + Execute (true); - if (!Connection.Tds.NextResult () || !Connection.Tds.NextRow ()) - return null; + try { + if (Connection.Tds.NextResult () && Connection.Tds.NextRow ()) + result = Connection.Tds.ColumnValues[0]; - object result = Connection.Tds.ColumnValues [0]; - CloseDataReader (true); - return result; + if (commandType == CommandType.StoredProcedure) { + Connection.Tds.SkipToEnd (); + GetOutputParameters (); + } + } catch (TdsTimeoutException ex) { + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } + + return result; + } finally { + CloseDataReader (); + } } public XmlReader ExecuteXmlReader () { - ValidateCommand ("ExecuteXmlReader"); - behavior = CommandBehavior.Default; - try { - Execute (CommandBehavior.Default, true); - } - catch (TdsTimeoutException e) { + ValidateCommand ("ExecuteXmlReader", false); + behavior = CommandBehavior.Default; + try { + Execute (true); + } catch (TdsTimeoutException e) { + Connection.Tds.Reset (); throw SqlException.FromTdsInternalException ((TdsInternalException) e); } @@ -481,7 +666,8 @@ namespace System.Data.SqlClient { int index = 0; foreach (SqlParameter parameter in parameters) { - if (parameter.Direction != ParameterDirection.Input) { + if (parameter.Direction != ParameterDirection.Input && + parameter.Direction != ParameterDirection.ReturnValue) { parameter.Value = list [index]; index += 1; } @@ -493,10 +679,11 @@ namespace System.Data.SqlClient { object ICloneable.Clone () { - return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout, parameters); + return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout, parameters); } +#if !NET_2_0 IDbDataParameter IDbCommand.CreateParameter () { return CreateParameter (); @@ -511,22 +698,42 @@ namespace System.Data.SqlClient { { return ExecuteReader (behavior); } +#endif - public #if NET_2_0 - override + protected override void Dispose (bool disposing) + { + if (disposed) return; + if (disposing) { + parameters.Clear(); + if (Connection != null) + Connection.DataReader = null; + } + base.Dispose (disposing); + disposed = true; + } +#endif + + public +#if NET_2_0 + override #endif // NET_2_0 - void Prepare () + void Prepare () { - ValidateCommand ("Prepare"); +#if NET_2_0 + if (Connection == null) + throw new NullReferenceException (); +#endif - if (CommandType == CommandType.StoredProcedure) + if (CommandType == CommandType.StoredProcedure || CommandType == CommandType.Text && Parameters.Count == 0) return; + ValidateCommand ("Prepare", false); + try { foreach (SqlParameter param in Parameters) param.CheckIfInitialized (); - }catch (Exception e) { + } catch (Exception e) { throw new InvalidOperationException ("SqlCommand.Prepare requires " + e.Message); } @@ -535,7 +742,7 @@ namespace System.Data.SqlClient { public void ResetCommandTimeout () { - commandTimeout = 30; + commandTimeout = DEFAULT_COMMAND_TIMEOUT; } private void Unprepare () @@ -544,74 +751,74 @@ namespace System.Data.SqlClient { preparedStatement = null; } - private void ValidateCommand (string method) + private void ValidateCommand (string method, bool async) { if (Connection == null) - throw new InvalidOperationException (String.Format ("{0} requires a Connection object to continue.", method)); - if (Connection.Transaction != null && transaction != Connection.Transaction) - throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object."); + throw new InvalidOperationException (String.Format ("{0}: A Connection object is required to continue.", method)); + if (Transaction == null && Connection.Transaction != null) + throw new InvalidOperationException (String.Format ( + "{0} requires a transaction if the command's connection is in a pending transaction.", +#if NET_2_0 + method)); +#else + "Execute")); +#endif + if (Transaction != null && Transaction.Connection != Connection) + throw new InvalidOperationException ("The connection does not have the same transaction as the command."); if (Connection.State != ConnectionState.Open) - throw new InvalidOperationException (String.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method)); - if (commandText == String.Empty || commandText == null) - throw new InvalidOperationException ("The command text for this Command has not been set."); + throw new InvalidOperationException (String.Format ("{0} requires an open connection to continue. This connection is closed.", method)); + if (CommandText.Length == 0) + throw new InvalidOperationException (String.Format ("{0}: CommandText has not been set for this Command.", method)); if (Connection.DataReader != null) throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first."); if (Connection.XmlReader != null) throw new InvalidOperationException ("There is already an open XmlReader associated with this Connection which must be closed first."); #if NET_2_0 - if (method.StartsWith ("Begin") && !Connection.AsyncProcessing) - throw new InvalidOperationException ("This Connection object is not " + - "in Asynchronous mode. Use 'Asynchronous" + - " Processing = true' to set it."); + if (async && !Connection.AsyncProcessing) + throw new InvalidOperationException ("This Connection object is not " + + "in Asynchronous mode. Use 'Asynchronous" + + " Processing = true' to set it."); #endif // NET_2_0 } #if NET_2_0 - [MonoTODO] - protected override DbParameter CreateDbParameter () - { - return (DbParameter) CreateParameter (); - } - - [MonoTODO] - protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior) - { - return (DbDataReader) ExecuteReader (behavior); - } - - [MonoTODO] - protected override DbConnection DbConnection - { - get { return (DbConnection) Connection; } - set { Connection = (SqlConnection) value; } - } - - [MonoTODO] - protected override DbParameterCollection DbParameterCollection - { - get { return (DbParameterCollection) Parameters; } - } - - [MonoTODO] - protected override DbTransaction DbTransaction - { - get { return (DbTransaction) Transaction; } - set { Transaction = (SqlTransaction) value; } - } + protected override DbParameter CreateDbParameter () + { + return CreateParameter (); + } + + protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior) + { + return ExecuteReader (behavior); + } + + protected override DbConnection DbConnection { + get { return Connection; } + set { Connection = (SqlConnection) value; } + } + + protected override DbParameterCollection DbParameterCollection { + get { return Parameters; } + } + + protected override DbTransaction DbTransaction { + get { return Transaction; } + set { Transaction = (SqlTransaction) value; } + } #endif // NET_2_0 #endregion // Methods #if NET_2_0 - #region Asynchronous Methods - - internal IAsyncResult BeginExecuteInternal (CommandBehavior behavior, - bool wantResults, - AsyncCallback callback, - object state) - { - IAsyncResult ar = null; - Connection.Tds.RecordsAffected = -1; + #region Asynchronous Methods + + internal IAsyncResult BeginExecuteInternal (CommandBehavior behavior, + bool wantResults, + AsyncCallback callback, + object state) + { + IAsyncResult ar = null; + Connection.Tds.RecordsAffected = -1; TdsMetaParameterCollection parms = Parameters.MetaParameters; if (preparedStatement == null) { bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0); @@ -630,174 +837,189 @@ namespace System.Data.SqlClient { sql1.Append ("SET FMTONLY ON;"); sql2.Append ("SET FMTONLY OFF;"); } - switch (CommandType) { case CommandType.StoredProcedure: - string prolog = ""; - string epilog = ""; + string prolog = ""; + string epilog = ""; if (keyInfo || schemaOnly) prolog = sql1.ToString (); - if (keyInfo || schemaOnly) + if (keyInfo || schemaOnly) epilog = sql2.ToString (); - Connection.Tds.BeginExecuteProcedure (prolog, - epilog, - CommandText, - !wantResults, - parms, - callback, - state); - + try { + Connection.Tds.BeginExecuteProcedure (prolog, + epilog, + CommandText, + !wantResults, + parms, + callback, + state); + } catch (TdsTimeoutException ex) { + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } break; case CommandType.Text: string sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ()); - if (wantResults) - ar = Connection.Tds.BeginExecuteQuery (sql, parms, - callback, state); - else - ar = Connection.Tds.BeginExecuteNonQuery (sql, parms, callback, state); + try { + if (wantResults) + ar = Connection.Tds.BeginExecuteQuery (sql, parms, callback, state); + else + ar = Connection.Tds.BeginExecuteNonQuery (sql, parms, callback, state); + } catch (TdsTimeoutException ex) { + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } break; } } - else - Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults); - - return ar; - - } - - internal void EndExecuteInternal (IAsyncResult ar) - { - SqlAsyncResult sqlResult = ( (SqlAsyncResult) ar); - Connection.Tds.WaitFor (sqlResult.InternalResult); - Connection.Tds.CheckAndThrowException (sqlResult.InternalResult); - } - - public IAsyncResult BeginExecuteNonQuery () - { - return BeginExecuteNonQuery (null, null); - } - - public IAsyncResult BeginExecuteNonQuery (AsyncCallback callback, object state) - { - ValidateCommand ("BeginExecuteNonQuery"); - SqlAsyncResult ar = new SqlAsyncResult (callback, state); - ar.EndMethod = "EndExecuteNonQuery"; - ar.InternalResult = BeginExecuteInternal (CommandBehavior.Default, false, ar.BubbleCallback, ar); - return ar; - } - - public int EndExecuteNonQuery (IAsyncResult ar) - { - ValidateAsyncResult (ar, "EndExecuteNonQuery"); - EndExecuteInternal (ar); - + else { + try { + Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults); + } catch (TdsTimeoutException ex) { + Connection.Tds.Reset (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } catch (TdsInternalException ex) { + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) ex); + } + } + return ar; + } + + internal void EndExecuteInternal (IAsyncResult ar) + { + SqlAsyncResult sqlResult = ( (SqlAsyncResult) ar); + Connection.Tds.WaitFor (sqlResult.InternalResult); + Connection.Tds.CheckAndThrowException (sqlResult.InternalResult); + } + + public IAsyncResult BeginExecuteNonQuery () + { + return BeginExecuteNonQuery (null, null); + } + + public IAsyncResult BeginExecuteNonQuery (AsyncCallback callback, object stateObject) + { + ValidateCommand ("BeginExecuteNonQuery", true); + SqlAsyncResult ar = new SqlAsyncResult (callback, stateObject); + ar.EndMethod = "EndExecuteNonQuery"; + ar.InternalResult = BeginExecuteInternal (CommandBehavior.Default, false, ar.BubbleCallback, ar); + return ar; + } + + public int EndExecuteNonQuery (IAsyncResult asyncResult) + { + ValidateAsyncResult (asyncResult, "EndExecuteNonQuery"); + EndExecuteInternal (asyncResult); + int ret = Connection.Tds.RecordsAffected; - GetOutputParameters (); - ( (SqlAsyncResult) ar).Ended = true; - return ret; - } - - public IAsyncResult BeginExecuteReader () - { - return BeginExecuteReader (null, null, CommandBehavior.Default); - } - - public IAsyncResult BeginExecuteReader (CommandBehavior behavior) - { - return BeginExecuteReader (null, null, behavior); - } - - public IAsyncResult BeginExecuteReader (AsyncCallback callback, object state) - { - return BeginExecuteReader (callback, state, CommandBehavior.Default); - } - - public IAsyncResult BeginExecuteReader (AsyncCallback callback, object state, CommandBehavior behavior) - { - ValidateCommand ("BeginExecuteReader"); - this.behavior = behavior; - SqlAsyncResult ar = new SqlAsyncResult (callback, state); - ar.EndMethod = "EndExecuteReader"; - IAsyncResult tdsResult = BeginExecuteInternal (behavior, true, - ar.BubbleCallback, state); - ar.InternalResult = tdsResult; - return ar; - } - - public SqlDataReader EndExecuteReader (IAsyncResult ar) - { - ValidateAsyncResult (ar, "EndExecuteReader"); - EndExecuteInternal (ar); - SqlDataReader reader = null; - try { - reader = new SqlDataReader (this); + GetOutputParameters (); + ((SqlAsyncResult) asyncResult).Ended = true; + return ret; + } + + public IAsyncResult BeginExecuteReader () + { + return BeginExecuteReader (null, null, CommandBehavior.Default); + } + + public IAsyncResult BeginExecuteReader (CommandBehavior behavior) + { + return BeginExecuteReader (null, null, behavior); + } + + public IAsyncResult BeginExecuteReader (AsyncCallback callback, object stateObject) + { + return BeginExecuteReader (callback, stateObject, CommandBehavior.Default); + } + + public IAsyncResult BeginExecuteReader (AsyncCallback callback, object stateObject, CommandBehavior behavior) + { + ValidateCommand ("BeginExecuteReader", true); + this.behavior = behavior; + SqlAsyncResult ar = new SqlAsyncResult (callback, stateObject); + ar.EndMethod = "EndExecuteReader"; + IAsyncResult tdsResult = BeginExecuteInternal (behavior, true, + ar.BubbleCallback, stateObject); + ar.InternalResult = tdsResult; + return ar; + } + + public SqlDataReader EndExecuteReader (IAsyncResult asyncResult) + { + ValidateAsyncResult (asyncResult, "EndExecuteReader"); + EndExecuteInternal (asyncResult); + SqlDataReader reader = null; + try { + reader = new SqlDataReader (this); + } catch (TdsTimeoutException e) { + throw SqlException.FromTdsInternalException ((TdsInternalException) e); + } catch (TdsInternalException e) { + // if behavior is closeconnection, even if it throws exception + // the connection has to be closed. + if ((behavior & CommandBehavior.CloseConnection) != 0) + Connection.Close (); + throw SqlException.FromTdsInternalException ((TdsInternalException) e); } - catch (TdsTimeoutException e) { - // if behavior is closeconnection, even if it throws exception - // the connection has to be closed. - if ((behavior & CommandBehavior.CloseConnection) != 0) - Connection.Close (); - throw SqlException.FromTdsInternalException ((TdsInternalException) e); - } catch (SqlException) { - // if behavior is closeconnection, even if it throws exception - // the connection has to be closed. - if ((behavior & CommandBehavior.CloseConnection) != 0) - Connection.Close (); - - throw; - } - - ( (SqlAsyncResult) ar).Ended = true; - return reader; - } - - public IAsyncResult BeginExecuteXmlReader (AsyncCallback callback, object state) - { - ValidateCommand ("BeginExecuteXmlReader"); - SqlAsyncResult ar = new SqlAsyncResult (callback, state); - ar.EndMethod = "EndExecuteXmlReader"; - ar.InternalResult = BeginExecuteInternal (behavior, true, - ar.BubbleCallback, state); - return ar; - } - - public XmlReader EndExecuteXmlReader (IAsyncResult ar) - { - ValidateAsyncResult (ar, "EndExecuteXmlReader"); - EndExecuteInternal (ar); - SqlDataReader reader = new SqlDataReader (this); - SqlXmlTextReader textReader = new SqlXmlTextReader (reader); - XmlReader xmlReader = new XmlTextReader (textReader); - ( (SqlAsyncResult) ar).Ended = true; - return xmlReader; - } - - - internal void ValidateAsyncResult (IAsyncResult ar, string endMethod) - { - if (ar == null) - throw new ArgumentException ("result passed is null!"); - if (! (ar is SqlAsyncResult)) - throw new ArgumentException (String.Format ("cannot test validity of types {0}", - ar.GetType () - )); - SqlAsyncResult result = (SqlAsyncResult) ar; - - if (result.EndMethod != endMethod) - throw new InvalidOperationException (String.Format ("Mismatched {0} called for AsyncResult. " + - "Expected call to {1} but {0} is called instead.", - endMethod, - result.EndMethod - )); - if (result.Ended) - throw new InvalidOperationException (String.Format ("The method {0} cannot be called " + - "more than once for the same AsyncResult.", - endMethod)); - - } - - #endregion // Asynchronous Methods + + ((SqlAsyncResult) asyncResult).Ended = true; + return reader; + } + + public IAsyncResult BeginExecuteXmlReader (AsyncCallback callback, object stateObject) + { + ValidateCommand ("BeginExecuteXmlReader", true); + SqlAsyncResult ar = new SqlAsyncResult (callback, stateObject); + ar.EndMethod = "EndExecuteXmlReader"; + ar.InternalResult = BeginExecuteInternal (behavior, true, + ar.BubbleCallback, stateObject); + return ar; + } + + public IAsyncResult BeginExecuteXmlReader () + { + return BeginExecuteXmlReader (null, null); + } + + + public XmlReader EndExecuteXmlReader (IAsyncResult asyncResult) + { + ValidateAsyncResult (asyncResult, "EndExecuteXmlReader"); + EndExecuteInternal (asyncResult); + SqlDataReader reader = new SqlDataReader (this); + SqlXmlTextReader textReader = new SqlXmlTextReader (reader); + XmlReader xmlReader = new XmlTextReader (textReader); + ((SqlAsyncResult) asyncResult).Ended = true; + return xmlReader; + } + + internal void ValidateAsyncResult (IAsyncResult ar, string endMethod) + { + if (ar == null) + throw new ArgumentException ("result passed is null!"); + if (! (ar is SqlAsyncResult)) + throw new ArgumentException (String.Format ("cannot test validity of types {0}", + ar.GetType ())); + SqlAsyncResult result = (SqlAsyncResult) ar; + if (result.EndMethod != endMethod) + throw new InvalidOperationException (String.Format ("Mismatched {0} called for AsyncResult. " + + "Expected call to {1} but {0} is called instead.", + endMethod, result.EndMethod)); + if (result.Ended) + throw new InvalidOperationException (String.Format ("The method {0} cannot be called " + + "more than once for the same AsyncResult.", endMethod)); + } + + #endregion // Asynchronous Methods + + public event StatementCompletedEventHandler StatementCompleted; #endif // NET_2_0 } }