Grasshopper now uses csproj instead of vmwcsproj
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlCommand.cs
1 //
2 // System.Data.SqlClient.SqlCommand.cs
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Daniel Morgan (danmorg@sc.rr.com)
7 //   Tim Coleman (tim@timcoleman.com)
8 //   Diego Caravana (diego@toth.it)
9 //
10 // (C) Ximian, Inc 2002 http://www.ximian.com/
11 // (C) Daniel Morgan, 2002
12 // Copyright (C) Tim Coleman, 2002
13 //
14
15 //
16 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
17 //
18 // Permission is hereby granted, free of charge, to any person obtaining
19 // a copy of this software and associated documentation files (the
20 // "Software"), to deal in the Software without restriction, including
21 // without limitation the rights to use, copy, modify, merge, publish,
22 // distribute, sublicense, and/or sell copies of the Software, and to
23 // permit persons to whom the Software is furnished to do so, subject to
24 // the following conditions:
25 // 
26 // The above copyright notice and this permission notice shall be
27 // included in all copies or substantial portions of the Software.
28 // 
29 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 //
37
38 using Mono.Data.Tds;
39 using Mono.Data.Tds.Protocol;
40 using System;
41 using System.Collections;
42 using System.Collections.Specialized;
43 using System.ComponentModel;
44 using System.Data;
45 using System.Data.Common;
46 using System.Runtime.InteropServices;
47 using System.Text;
48 using System.Xml;
49
50 namespace System.Data.SqlClient {
51         [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.SqlCommandDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
52          [ToolboxItemAttribute ("System.Drawing.Design.ToolboxItem, "+ Consts.AssemblySystem_Drawing)]
53 #if NET_2_0
54         public sealed class SqlCommand : DbCommand, IDbCommand, ICloneable
55 #else
56         public sealed class SqlCommand : Component, IDbCommand, ICloneable
57 #endif // NET_2_0
58         {
59                 #region Fields
60
61                 //bool disposed = false;
62                 int commandTimeout;
63                 bool designTimeVisible;
64                 string commandText;
65                 CommandType commandType;
66                 SqlConnection connection;
67                 SqlTransaction transaction;
68                 UpdateRowSource updatedRowSource;
69                 CommandBehavior behavior = CommandBehavior.Default;
70                 SqlParameterCollection parameters;
71                 string preparedStatement = null;
72
73                 #endregion // Fields
74
75                 #region Constructors
76
77                 public SqlCommand() 
78                         : this (String.Empty, null, null)
79                 {
80                 }
81
82                 public SqlCommand (string commandText) 
83                         : this (commandText, null, null)
84                 {
85                 }
86
87                 public SqlCommand (string commandText, SqlConnection connection) 
88                         : this (commandText, connection, null)
89                 {
90                 }
91
92                 public SqlCommand (string commandText, SqlConnection connection, SqlTransaction transaction) 
93                 {
94                         this.commandText = commandText;
95                         this.connection = connection;
96                         this.transaction = transaction;
97                         this.commandType = CommandType.Text;
98                         this.updatedRowSource = UpdateRowSource.Both;
99
100                         this.designTimeVisible = false;
101                         this.commandTimeout = 30;
102                         parameters = new SqlParameterCollection (this);
103                 }
104
105                 private SqlCommand(string commandText, SqlConnection connection, SqlTransaction transaction, CommandType commandType, UpdateRowSource updatedRowSource, bool designTimeVisible, int commandTimeout, SqlParameterCollection parameters)
106                 {
107                         this.commandText = commandText;
108                         this.connection = connection;
109                         this.transaction = transaction;
110                         this.commandType = commandType;
111                         this.updatedRowSource = updatedRowSource;
112                         this.designTimeVisible = designTimeVisible;
113                         this.commandTimeout = commandTimeout;
114                         this.parameters = new SqlParameterCollection(this);
115                         for (int i = 0;i < parameters.Count;i++)
116                               this.parameters.Add(((ICloneable)parameters[i]).Clone()); 
117                 }
118                 #endregion // Constructors
119
120                 #region Properties
121
122                 internal CommandBehavior CommandBehavior {
123                         get { return behavior; }
124                 }
125
126                 [DataCategory ("Data")]
127 #if !NET_2_0
128                 [DataSysDescription ("Command text to execute.")]
129 #endif
130                 [DefaultValue ("")]
131                 [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
132                 [RefreshProperties (RefreshProperties.All)]
133                 public 
134 #if NET_2_0
135                 override 
136 #endif //NET_2_0
137                 string CommandText {
138                         get { return commandText; }
139                         set { 
140                                 if (value != commandText && preparedStatement != null)
141                                         Unprepare ();
142                                 commandText = value; 
143                         }
144                 }
145
146 #if !NET_2_0
147                 [DataSysDescription ("Time to wait for command to execute.")]
148 #endif
149                 [DefaultValue (30)]
150                 public 
151 #if NET_2_0
152                 override
153 #endif //NET_2_0
154                 int CommandTimeout {
155                         get { return commandTimeout;  }
156                         set { 
157                                 if (value < 0)
158                                         throw new ArgumentException ("The property value assigned is less than 0.");
159                                 commandTimeout = value; 
160                         }
161                 }
162
163                 [DataCategory ("Data")]
164 #if !NET_2_0
165                 [DataSysDescription ("How to interpret the CommandText.")]
166 #endif
167                 [DefaultValue (CommandType.Text)]
168                 [RefreshProperties (RefreshProperties.All)]
169                 public 
170 #if NET_2_0
171                 override 
172 #endif //NET_2_0
173                 CommandType CommandType {
174                         get { return commandType; }
175                         set { 
176                                 if (value == CommandType.TableDirect)
177                                         throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono SqlClient Data Provider.");
178
179                                 if (!Enum.IsDefined (typeof (CommandType), value))
180                                         throw ExceptionHelper.InvalidEnumValueException ("CommandType", value);
181                                 commandType = value; 
182                         }
183                 }
184
185                 [DataCategory ("Behavior")]
186                 [DefaultValue (null)]
187 #if !NET_2_0
188                 [DataSysDescription ("Connection used by the command.")]
189 #endif
190                 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]                
191                 public 
192 #if NET_2_0
193                 new
194 #endif //NET_2_0
195                 SqlConnection Connection {
196                         get { return connection; }
197                         set { 
198                                 if (transaction != null && connection.Transaction != null && connection.Transaction.IsOpen)
199                                         throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress.");
200                                 transaction = null;
201                                 connection = value; 
202                         }
203                 }
204
205                 [Browsable (false)]
206                 [DefaultValue (true)]
207                 [DesignOnly (true)]
208                 public 
209 #if NET_2_0
210                 override
211 #endif //NET_2_0
212                 bool DesignTimeVisible {
213                         get { return designTimeVisible; } 
214                         set { designTimeVisible = value; }
215                 }
216
217                 [DataCategory ("Data")]
218 #if !NET_2_0
219                 [DataSysDescription ("The parameters collection.")]
220 #endif
221                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
222                 public 
223 #if NET_2_0
224                 new 
225 #endif //NET_2_0
226                 SqlParameterCollection Parameters {
227                         get { return parameters; }
228                 }
229
230                 internal ITds Tds {
231                         get { return Connection.Tds; }
232                 }
233
234                 IDbConnection IDbCommand.Connection {
235                         get { return Connection; }
236                         set { 
237                                 if (!(value is SqlConnection))
238                                         throw new InvalidCastException ("The value was not a valid SqlConnection.");
239                                 Connection = (SqlConnection) value;
240                         }
241                 }
242
243                 IDataParameterCollection IDbCommand.Parameters  {
244                         get { return Parameters; }
245                 }
246
247                 IDbTransaction IDbCommand.Transaction {
248                         get { return Transaction; }
249                         set { 
250                                 if (!(value is SqlTransaction))
251                                         throw new ArgumentException ();
252                                 Transaction = (SqlTransaction) value; 
253                         }
254                 }
255
256                 [Browsable (false)]
257 #if !NET_2_0
258                 [DataSysDescription ("The transaction used by the command.")]
259 #endif
260                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
261                 public new SqlTransaction Transaction {
262                         get { return transaction; }
263                         set { transaction = value; }
264                 }       
265
266                 [DataCategory ("Behavior")]
267 #if !NET_2_0
268                 [DataSysDescription ("When used by a DataAdapter.Update, how command results are applied to the current DataRow.")]
269 #endif
270                 [DefaultValue (UpdateRowSource.Both)]
271                 public 
272 #if NET_2_0
273                 override
274 #endif // NET_2_0
275                 UpdateRowSource UpdatedRowSource        {
276                         get { return updatedRowSource; }
277                         set { 
278                                 if (!Enum.IsDefined (typeof (UpdateRowSource), value))
279                                         throw ExceptionHelper.InvalidEnumValueException ("UpdateRowSource", value);
280                                 updatedRowSource = value;
281                         }
282                 }
283
284                 #endregion // Fields
285
286                 #region Methods
287
288                 public 
289 #if NET_2_0
290                 override
291 #endif // NET_2_0
292                 void Cancel () 
293                 {
294                         if (Connection == null || Connection.Tds == null)
295                                 return;
296                         Connection.Tds.Cancel ();
297                 }
298
299                 internal void CloseDataReader (bool moreResults)
300                 {
301                         Connection.DataReader = null;
302
303                         if ((behavior & CommandBehavior.CloseConnection) != 0)
304                                 Connection.Close ();
305
306                         // Reset the behavior
307                         behavior = CommandBehavior.Default;
308                         Tds.SequentialAccess = false;
309                 }
310
311                 public new SqlParameter CreateParameter () 
312                 {
313                         return new SqlParameter ();
314                 }
315
316                 internal void DeriveParameters ()
317                 {
318                         if (commandType != CommandType.StoredProcedure)
319                                 throw new InvalidOperationException (String.Format ("SqlCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
320                         ValidateCommand ("DeriveParameters");
321
322                         SqlParameterCollection localParameters = new SqlParameterCollection (this);
323                         localParameters.Add ("@procedure_name", SqlDbType.NVarChar, commandText.Length).Value = commandText;
324
325                         string sql = "sp_procedure_params_rowset";
326
327                         Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true);
328
329                         SqlDataReader reader = new SqlDataReader (this);
330                         parameters.Clear ();
331                         object[] dbValues = new object[reader.FieldCount];
332
333                         while (reader.Read ()) {
334                                 reader.GetValues (dbValues);
335                                 parameters.Add (new SqlParameter (dbValues));
336                         }
337                         reader.Close ();        
338
339                 }
340
341                 private void Execute (CommandBehavior behavior, bool wantResults)
342                 {
343                         Connection.Tds.RecordsAffected = -1;
344                         TdsMetaParameterCollection parms = Parameters.MetaParameters;
345                         if (preparedStatement == null) {
346                                 bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0);
347                                 bool keyInfo = ((behavior & CommandBehavior.KeyInfo) > 0);
348
349                                 StringBuilder sql1 = new StringBuilder ();
350                                 StringBuilder sql2 = new StringBuilder ();
351
352                                 if (schemaOnly || keyInfo)
353                                         sql1.Append ("SET FMTONLY OFF;");
354                                 if (keyInfo) {
355                                         sql1.Append ("SET NO_BROWSETABLE ON;");
356                                         sql2.Append ("SET NO_BROWSETABLE OFF;");
357                                 }
358                                 if (schemaOnly) {
359                                         sql1.Append ("SET FMTONLY ON;");
360                                         sql2.Append ("SET FMTONLY OFF;");
361                                 }
362
363                                 switch (CommandType) {
364                                 case CommandType.StoredProcedure:
365                                         if (keyInfo || schemaOnly)
366                                                 Connection.Tds.Execute (sql1.ToString ());
367                                         Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults);
368                                         if (keyInfo || schemaOnly)
369                                                 Connection.Tds.Execute (sql2.ToString ());
370                                         break;
371                                 case CommandType.Text:
372                                         //string sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ());
373                                         string sql;
374                                         if (sql2.Length > 0) {
375                                                 sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ());
376                                         } else {
377                                                 sql = String.Format ("{0}{1}", sql1.ToString (), CommandText);
378                                         }
379                                         Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults);
380                                         break;
381                                 }
382                         }
383                         else 
384                                 Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
385                 }
386
387                 public 
388 #if NET_2_0
389                 override
390 #endif // NET_2_0
391                 int ExecuteNonQuery ()
392                 {
393                         ValidateCommand ("ExecuteNonQuery");
394                         int result = 0;
395                         behavior = CommandBehavior.Default;
396
397                         try {
398                                 Execute (CommandBehavior.Default, false);
399                                 result = Connection.Tds.RecordsAffected;
400                         }
401                         catch (TdsTimeoutException e) {
402                                 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
403                         }
404
405                         GetOutputParameters ();
406                         return result;
407                 }
408
409                 public new SqlDataReader ExecuteReader ()
410                 {
411                         return ExecuteReader (CommandBehavior.Default);
412                 }
413
414                 public new SqlDataReader ExecuteReader (CommandBehavior behavior)
415                 {
416                         ValidateCommand ("ExecuteReader");
417                         try {
418                                 this.behavior = behavior;
419                                 if ((behavior & CommandBehavior.SequentialAccess) != 0)
420                                         Tds.SequentialAccess = true;
421                                 Execute (behavior, true);
422                                 Connection.DataReader = new SqlDataReader (this);
423                         }
424                         catch (TdsTimeoutException e) {
425                                 // if behavior is closeconnection, even if it throws exception
426                                 // the connection has to be closed.
427                                 if ((behavior & CommandBehavior.CloseConnection) != 0)
428                                         Connection.Close ();
429                                 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
430                         } catch (SqlException) {
431                                 // if behavior is closeconnection, even if it throws exception
432                                 // the connection has to be closed.
433                                 if ((behavior & CommandBehavior.CloseConnection) != 0)
434                                         Connection.Close ();
435
436                                 throw;
437                         }
438
439                         return Connection.DataReader;
440                 }
441
442                 public 
443 #if NET_2_0
444                 override
445 #endif // NET_2_0
446                 object ExecuteScalar ()
447                 {
448                         ValidateCommand ("ExecuteScalar");
449                         behavior = CommandBehavior.Default;
450                         try {
451                                 Execute (CommandBehavior.Default, true);
452                         }
453                         catch (TdsTimeoutException e) {
454                                 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
455                         }
456
457                         if (!Connection.Tds.NextResult () || !Connection.Tds.NextRow ())
458                                 return null;
459
460                         object result = Connection.Tds.ColumnValues [0];
461                         CloseDataReader (true);
462                         return result;
463                 }
464
465                 public XmlReader ExecuteXmlReader ()
466                 {
467                         ValidateCommand ("ExecuteXmlReader");
468                         behavior = CommandBehavior.Default;
469                         try { 
470                                 Execute (CommandBehavior.Default, true);
471                         }
472                         catch (TdsTimeoutException e) {
473                                 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
474                         }
475
476                         SqlDataReader dataReader = new SqlDataReader (this);
477                         SqlXmlTextReader textReader = new SqlXmlTextReader (dataReader);
478                         XmlReader xmlReader = new XmlTextReader (textReader);
479                         return xmlReader;
480                 }
481
482                 internal void GetOutputParameters ()
483                 {
484                         IList list = Connection.Tds.OutputParameters;
485
486                         if (list != null && list.Count > 0) {
487
488                                 int index = 0;
489                                 foreach (SqlParameter parameter in parameters) {
490                                         if (parameter.Direction != ParameterDirection.Input) {
491                                                 parameter.Value = list [index];
492                                                 index += 1;
493                                         }
494                                         if (index >= list.Count)
495                                                 break;
496                                 }
497                         }
498                 }
499
500                 object ICloneable.Clone ()
501                 {
502                         return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout,  parameters);
503
504                 }
505
506                 IDbDataParameter IDbCommand.CreateParameter ()
507                 {
508                         return CreateParameter ();
509                 }
510
511                 IDataReader IDbCommand.ExecuteReader ()
512                 {
513                         return ExecuteReader ();
514                 }
515
516                 IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
517                 {
518                         return ExecuteReader (behavior);
519                 }
520
521                 public 
522 #if NET_2_0
523                 override
524 #endif // NET_2_0
525                 void Prepare ()
526                 {
527                         ValidateCommand ("Prepare");
528
529                         if (CommandType == CommandType.StoredProcedure)
530                                 return;
531
532                         try {
533                                 foreach (SqlParameter param in Parameters)
534                                         param.CheckIfInitialized ();
535                         }catch (Exception e) {
536                                 throw new InvalidOperationException ("SqlCommand.Prepare requires " + e.Message);
537                         }
538
539                         preparedStatement = Connection.Tds.Prepare (CommandText, Parameters.MetaParameters);
540                 }
541
542                 public void ResetCommandTimeout ()
543                 {
544                         commandTimeout = 30;
545                 }
546
547                 private void Unprepare ()
548                 {
549                         Connection.Tds.Unprepare (preparedStatement);
550                         preparedStatement = null;
551                 }
552
553                 private void ValidateCommand (string method)
554                 {
555                         if (Connection == null)
556                                 throw new InvalidOperationException (String.Format ("{0} requires a Connection object to continue.", method));
557                         if (Connection.Transaction != null && transaction != Connection.Transaction)
558                                 throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object.");
559                         if (Connection.State != ConnectionState.Open)
560                                 throw new InvalidOperationException (String.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method));
561                         if (commandText == String.Empty || commandText == null)
562                                 throw new InvalidOperationException ("The command text for this Command has not been set.");
563                         if (Connection.DataReader != null)
564                                 throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
565                         if (Connection.XmlReader != null)
566                                 throw new InvalidOperationException ("There is already an open XmlReader associated with this Connection which must be closed first.");
567 #if NET_2_0
568                         if (method.StartsWith ("Begin") && !Connection.AsyncProcessing)
569                                 throw new InvalidOperationException ("This Connection object is not " + 
570                                                                      "in Asynchronous mode. Use 'Asynchronous" +
571                                                                      " Processing = true' to set it.");
572 #endif // NET_2_0
573                 }
574
575 #if NET_2_0
576                 protected override DbParameter CreateDbParameter ()
577                 {
578                         return (DbParameter) CreateParameter ();
579                 }
580
581                 protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
582                 {
583                         return (DbDataReader) ExecuteReader (behavior);
584                 }
585
586                 protected override DbConnection DbConnection 
587                 {
588                         get { return (DbConnection) Connection;  }
589                         set { Connection = (SqlConnection) value; }
590                 }
591                 
592                 protected override DbParameterCollection DbParameterCollection
593                 {
594                         get { return (DbParameterCollection) Parameters; }
595                 }
596
597                 protected override DbTransaction DbTransaction 
598                 {
599                         get { return (DbTransaction) Transaction; }
600                         set { Transaction = (SqlTransaction) value; }
601                 }
602 #endif // NET_2_0
603
604                 #endregion // Methods
605
606 #if NET_2_0
607                 #region Asynchronous Methods
608
609                 internal IAsyncResult BeginExecuteInternal (CommandBehavior behavior, 
610                                                             bool wantResults,
611                                                             AsyncCallback callback, 
612                                                             object state)
613                 {
614                         IAsyncResult ar = null;
615                         Connection.Tds.RecordsAffected = -1;
616                         TdsMetaParameterCollection parms = Parameters.MetaParameters;
617                         if (preparedStatement == null) {
618                                 bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0);
619                                 bool keyInfo = ((behavior & CommandBehavior.KeyInfo) > 0);
620
621                                 StringBuilder sql1 = new StringBuilder ();
622                                 StringBuilder sql2 = new StringBuilder ();
623
624                                 if (schemaOnly || keyInfo)
625                                         sql1.Append ("SET FMTONLY OFF;");
626                                 if (keyInfo) {
627                                         sql1.Append ("SET NO_BROWSETABLE ON;");
628                                         sql2.Append ("SET NO_BROWSETABLE OFF;");
629                                 }
630                                 if (schemaOnly) {
631                                         sql1.Append ("SET FMTONLY ON;");
632                                         sql2.Append ("SET FMTONLY OFF;");
633                                 }
634
635                                 switch (CommandType) {
636                                 case CommandType.StoredProcedure:
637                                         string prolog = "";
638                                         string epilog = "";
639                                         if (keyInfo || schemaOnly)
640                                                 prolog = sql1.ToString ();
641                                         if (keyInfo || schemaOnly)
642                                                 epilog = sql2.ToString ();
643                                         Connection.Tds.BeginExecuteProcedure (prolog,
644                                                                               epilog,
645                                                                               CommandText,
646                                                                               !wantResults,
647                                                                               parms,
648                                                                               callback,
649                                                                               state);
650                                                                               
651                                         break;
652                                 case CommandType.Text:
653                                         string sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ());
654                                         if (wantResults)
655                                                 ar = Connection.Tds.BeginExecuteQuery (sql, parms, 
656                                                                                        callback, state);
657                                         else
658                                                 ar = Connection.Tds.BeginExecuteNonQuery (sql, parms, callback, state);
659                                         break;
660                                 }
661                         }
662                         else 
663                                 Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
664
665                         return ar;
666
667                 }
668
669                 internal void EndExecuteInternal (IAsyncResult ar)
670                 {
671                         SqlAsyncResult sqlResult = ( (SqlAsyncResult) ar);
672                         Connection.Tds.WaitFor (sqlResult.InternalResult);
673                         Connection.Tds.CheckAndThrowException (sqlResult.InternalResult);
674                 }
675
676                 public IAsyncResult BeginExecuteNonQuery ()
677                 {
678                         return BeginExecuteNonQuery (null, null);
679                 }
680
681                 public IAsyncResult BeginExecuteNonQuery (AsyncCallback callback, object state)
682                 {
683                         ValidateCommand ("BeginExecuteNonQuery");
684                         SqlAsyncResult ar = new SqlAsyncResult (callback, state);
685                         ar.EndMethod = "EndExecuteNonQuery";
686                         ar.InternalResult = BeginExecuteInternal (CommandBehavior.Default, false, ar.BubbleCallback, ar);
687                         return ar;
688                 }
689
690                 public int EndExecuteNonQuery (IAsyncResult ar)
691                 {
692                         ValidateAsyncResult (ar, "EndExecuteNonQuery");
693                         EndExecuteInternal (ar);
694                         
695                         int ret = Connection.Tds.RecordsAffected;
696
697                         GetOutputParameters ();
698                         ( (SqlAsyncResult) ar).Ended = true;
699                         return ret;
700                 }
701
702                 public IAsyncResult BeginExecuteReader ()
703                 {
704                         return BeginExecuteReader (null, null, CommandBehavior.Default);
705                 }
706
707                 public IAsyncResult BeginExecuteReader (CommandBehavior behavior)
708                 {
709                         return BeginExecuteReader (null, null, behavior);
710                 }
711                 
712                 public IAsyncResult BeginExecuteReader (AsyncCallback callback, object state)
713                 {
714                         return BeginExecuteReader (callback, state, CommandBehavior.Default);
715                 }
716
717                 public IAsyncResult BeginExecuteReader (AsyncCallback callback, object state, CommandBehavior behavior)
718                 {
719                         ValidateCommand ("BeginExecuteReader");
720                         this.behavior = behavior;
721                         SqlAsyncResult ar = new SqlAsyncResult (callback, state);
722                         ar.EndMethod = "EndExecuteReader";
723                         IAsyncResult tdsResult = BeginExecuteInternal (behavior, true, 
724                                                                        ar.BubbleCallback, state);
725                         ar.InternalResult = tdsResult;
726                         return ar;
727                 }
728
729                 public SqlDataReader EndExecuteReader (IAsyncResult ar)
730                 {
731                         ValidateAsyncResult (ar, "EndExecuteReader");
732                         EndExecuteInternal (ar);
733                         SqlDataReader reader = null;
734                         try {
735                                 reader = new SqlDataReader (this);
736                         }
737                         catch (TdsTimeoutException e) {
738                                 // if behavior is closeconnection, even if it throws exception
739                                 // the connection has to be closed.
740                                 if ((behavior & CommandBehavior.CloseConnection) != 0)
741                                         Connection.Close ();
742                                 throw SqlException.FromTdsInternalException ((TdsInternalException) e);
743                         } catch (SqlException) {
744                                 // if behavior is closeconnection, even if it throws exception
745                                 // the connection has to be closed.
746                                 if ((behavior & CommandBehavior.CloseConnection) != 0)
747                                         Connection.Close ();
748
749                                 throw;
750                         }
751
752                         ( (SqlAsyncResult) ar).Ended = true;
753                         return reader;
754                 }
755
756                 public IAsyncResult BeginExecuteXmlReader (AsyncCallback callback, object state)
757                 {
758                         ValidateCommand ("BeginExecuteXmlReader");
759                         SqlAsyncResult ar = new SqlAsyncResult (callback, state);
760                         ar.EndMethod = "EndExecuteXmlReader";
761                         ar.InternalResult = BeginExecuteInternal (behavior, true, 
762                                                                        ar.BubbleCallback, state);
763                         return ar;
764                 }
765
766                 public XmlReader EndExecuteXmlReader (IAsyncResult ar)
767                 {
768                         ValidateAsyncResult (ar, "EndExecuteXmlReader");
769                         EndExecuteInternal (ar);
770                         SqlDataReader reader = new SqlDataReader (this);
771                         SqlXmlTextReader textReader = new SqlXmlTextReader (reader);
772                         XmlReader xmlReader = new XmlTextReader (textReader);
773                         ( (SqlAsyncResult) ar).Ended = true;
774                         return xmlReader;
775                 }
776
777
778                 internal void ValidateAsyncResult (IAsyncResult ar, string endMethod)
779                 {
780                         if (ar == null)
781                                 throw new ArgumentException ("result passed is null!");
782                         if (! (ar is SqlAsyncResult))
783                                 throw new ArgumentException (String.Format ("cannot test validity of types {0}",
784                                                                             ar.GetType ()
785                                                                             ));
786                         SqlAsyncResult result = (SqlAsyncResult) ar;
787                         
788                         if (result.EndMethod != endMethod)
789                                 throw new InvalidOperationException (String.Format ("Mismatched {0} called for AsyncResult. " + 
790                                                                                     "Expected call to {1} but {0} is called instead.",
791                                                                                     endMethod,
792                                                                                     result.EndMethod
793                                                                                     ));
794                         if (result.Ended)
795                                 throw new InvalidOperationException (String.Format ("The method {0}  cannot be called " + 
796                                                                                     "more than once for the same AsyncResult.",
797                                                                                     endMethod));
798
799                 }
800
801                 #endregion // Asynchronous Methods
802                 public event StatementCompletedEventHandler StatementCompleted;
803 #endif // NET_2_0
804         }
805 }