2 // Mono.Data.TdsClient.TdsCommand.cs
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Daniel Morgan (danmorg@sc.rr.com)
7 // Tim Coleman (tim@timcoleman.com)
9 // (C) Ximian, Inc 2002 http://www.ximian.com/
10 // (C) Daniel Morgan, 2002
11 // Copyright (C) Tim Coleman, 2002
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using Mono
.Data
.Tds
.Protocol
;
38 using System
.Collections
;
39 using System
.Collections
.Specialized
;
40 using System
.ComponentModel
;
42 using System
.Data
.Common
;
43 using System
.Runtime
.InteropServices
;
46 namespace Mono
.Data
.TdsClient
{
47 public sealed class TdsCommand
: Component
, IDbCommand
, ICloneable
51 bool disposed
= false;
53 bool designTimeVisible
;
55 CommandType commandType
;
56 TdsConnection connection
;
57 TdsTransaction transaction
;
58 UpdateRowSource updatedRowSource
;
59 CommandBehavior behavior
= CommandBehavior
.Default
;
60 TdsParameterCollection parameters
;
67 : this (String
.Empty
, null, null)
71 public TdsCommand (string commandText
)
72 : this (commandText
, null, null)
74 commandText
= commandText
;
77 public TdsCommand (string commandText
, TdsConnection connection
)
78 : this (commandText
, connection
, null)
80 Connection
= connection
;
83 public TdsCommand (string commandText
, TdsConnection connection
, TdsTransaction transaction
)
85 this.commandText
= commandText
;
86 this.connection
= connection
;
87 this.transaction
= transaction
;
88 this.commandType
= CommandType
.Text
;
89 this.updatedRowSource
= UpdateRowSource
.Both
;
91 this.designTimeVisible
= false;
92 this.commandTimeout
= 30;
93 parameters
= new TdsParameterCollection (this);
96 #endregion // Constructors
100 internal CommandBehavior CommandBehavior
{
101 get { return behavior; }
104 public string CommandText
{
105 get { return commandText; }
106 set { commandText = value; }
109 public int CommandTimeout
{
110 get { return commandTimeout; }
112 if (commandTimeout
< 0)
113 throw new ArgumentException ("The property value assigned is less than 0.");
114 commandTimeout
= value;
118 public CommandType CommandType
{
119 get { return commandType; }
121 if (value == CommandType
.TableDirect
)
122 throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono TdsClient Data Provider.");
127 public TdsConnection Connection
{
128 get { return connection; }
130 if (transaction
!= null && connection
.Transaction
!= null && connection
.Transaction
.IsOpen
)
131 throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress.");
137 public bool DesignTimeVisible
{
138 get { return designTimeVisible; }
139 set { designTimeVisible = value; }
142 public TdsParameterCollection Parameters
{
143 get { return parameters; }
147 get { return Connection.Tds; }
150 IDbConnection IDbCommand
.Connection
{
151 get { return Connection; }
153 if (!(value is TdsConnection
))
154 throw new InvalidCastException ("The value was not a valid TdsConnection.");
155 Connection
= (TdsConnection
) value;
159 IDataParameterCollection IDbCommand
.Parameters
{
160 get { return Parameters; }
163 IDbTransaction IDbCommand
.Transaction
{
164 get { return Transaction; }
166 if (!(value is TdsTransaction
))
167 throw new ArgumentException ();
168 Transaction
= (TdsTransaction
) value;
172 public TdsTransaction Transaction
{
173 get { return transaction; }
174 set { transaction = value; }
177 public UpdateRowSource UpdatedRowSource
{
178 get { return updatedRowSource; }
179 set { updatedRowSource = value; }
186 public void Cancel ()
188 if (Connection
== null || Connection
.Tds
== null)
190 Connection
.Tds
.Cancel ();
193 internal void CloseDataReader (bool moreResults
)
195 GetOutputParameters ();
196 Connection
.DataReader
= null;
198 if ((behavior
& CommandBehavior
.CloseConnection
) != 0)
202 public TdsParameter
CreateParameter ()
204 return new TdsParameter ();
207 internal void DeriveParameters ()
209 if (commandType
!= CommandType
.StoredProcedure
)
210 throw new InvalidOperationException (String
.Format ("TdsCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType
));
211 ValidateCommand ("DeriveParameters");
213 TdsParameterCollection localParameters
= new TdsParameterCollection (this);
214 localParameters
.Add ("@P1", TdsType
.NVarChar
, commandText
.Length
).Value
= commandText
;
216 string sql
= "sp_procedure_params_rowset";
218 Connection
.Tds
.ExecProc (sql
, localParameters
.MetaParameters
, 0, true);
220 TdsDataReader reader
= new TdsDataReader (this);
222 object[] dbValues
= new object[reader
.FieldCount
];
224 while (reader
.Read ()) {
225 reader
.GetValues (dbValues
);
226 parameters
.Add (new TdsParameter (dbValues
));
231 private void Execute (CommandBehavior behavior
, bool wantResults
)
233 TdsMetaParameterCollection parms
= Parameters
.MetaParameters
;
234 bool schemaOnly
= ((CommandBehavior
& CommandBehavior
.SchemaOnly
) > 0);
235 bool keyInfo
= ((CommandBehavior
& CommandBehavior
.SchemaOnly
) > 0);
237 StringBuilder sql1
= new StringBuilder ();
238 StringBuilder sql2
= new StringBuilder ();
240 if (schemaOnly
|| keyInfo
)
241 sql1
.Append ("SET FMTONLY OFF;");
243 sql1
.Append ("SET NO_BROWSETABLE ON;");
244 sql2
.Append ("SET NO_BROWSETABLE OFF;");
247 sql1
.Append ("SET FMTONLY ON;");
248 sql2
.Append ("SET FMTONLY OFF;");
251 switch (CommandType
) {
252 case CommandType
.StoredProcedure
:
253 if (keyInfo
|| schemaOnly
)
254 Connection
.Tds
.Execute (sql1
.ToString ());
255 Connection
.Tds
.ExecProc (CommandText
, parms
, CommandTimeout
, wantResults
);
256 if (keyInfo
|| schemaOnly
)
257 Connection
.Tds
.Execute (sql2
.ToString ());
259 case CommandType
.Text
:
260 string sql
= String
.Format ("{0}{1}{2}", sql1
.ToString (), CommandText
, sql2
.ToString ());
261 Connection
.Tds
.Execute (sql
, parms
, CommandTimeout
, wantResults
);
266 public int ExecuteNonQuery ()
268 ValidateCommand ("ExecuteNonQuery");
272 Execute (CommandBehavior
.Default
, false);
274 catch (TdsTimeoutException e
) {
275 throw TdsException
.FromTdsInternalException ((TdsInternalException
) e
);
278 GetOutputParameters ();
282 public TdsDataReader
ExecuteReader ()
284 return ExecuteReader (CommandBehavior
.Default
);
287 public TdsDataReader
ExecuteReader (CommandBehavior behavior
)
289 ValidateCommand ("ExecuteReader");
291 Execute (behavior
, true);
293 catch (TdsTimeoutException e
) {
294 throw TdsException
.FromTdsInternalException ((TdsInternalException
) e
);
296 Connection
.DataReader
= new TdsDataReader (this);
297 return Connection
.DataReader
;
300 public object ExecuteScalar ()
302 ValidateCommand ("ExecuteScalar");
304 Execute (CommandBehavior
.Default
, true);
306 catch (TdsTimeoutException e
) {
307 throw TdsException
.FromTdsInternalException ((TdsInternalException
) e
);
310 if (!Connection
.Tds
.NextResult () || !Connection
.Tds
.NextRow ())
313 object result
= Connection
.Tds
.ColumnValues
[0];
314 CloseDataReader (true);
318 private void GetOutputParameters ()
320 Connection
.Tds
.SkipToEnd ();
322 IList list
= Connection
.Tds
.ColumnValues
;
324 if (list
!= null && list
.Count
> 0) {
326 foreach (TdsParameter parameter
in parameters
) {
327 if (parameter
.Direction
!= ParameterDirection
.Input
) {
328 parameter
.Value
= list
[index
];
331 if (index
>= list
.Count
)
337 object ICloneable
.Clone ()
339 return new TdsCommand (commandText
, Connection
);
342 IDbDataParameter IDbCommand
.CreateParameter ()
344 return CreateParameter ();
347 IDataReader IDbCommand
.ExecuteReader ()
349 return ExecuteReader ();
352 IDataReader IDbCommand
.ExecuteReader (CommandBehavior behavior
)
354 return ExecuteReader (behavior
);
357 public void Prepare ()
359 throw new NotSupportedException ("TdsClient does not support PREPARE.");
362 public void ResetCommandTimeout ()
367 private void ValidateCommand (string method
)
369 if (Connection
== null)
370 throw new InvalidOperationException (String
.Format ("{0} requires a Connection object to continue.", method
));
371 if (Connection
.Transaction
!= null && transaction
!= Connection
.Transaction
)
372 throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object.");
373 if (Connection
.State
!= ConnectionState
.Open
)
374 throw new InvalidOperationException (String
.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method
));
375 if (commandText
== String
.Empty
|| commandText
== null)
376 throw new InvalidOperationException ("The command text for this Command has not been set.");
377 if (Connection
.DataReader
!= null)
378 throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
381 #endregion // Methods