2 // Mono.Data.SybaseClient.SybaseCommand.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
.SybaseClient
{
47 public sealed class SybaseCommand
: Component
, IDbCommand
, ICloneable
51 bool disposed
= false;
53 bool designTimeVisible
;
55 CommandType commandType
;
56 SybaseConnection connection
;
57 SybaseTransaction transaction
;
58 UpdateRowSource updatedRowSource
;
59 CommandBehavior behavior
= CommandBehavior
.Default
;
60 SybaseParameterCollection parameters
;
61 string preparedStatement
= null;
67 public SybaseCommand()
68 : this (String
.Empty
, null, null)
72 public SybaseCommand (string commandText
)
73 : this (commandText
, null, null)
75 commandText
= commandText
;
78 public SybaseCommand (string commandText
, SybaseConnection connection
)
79 : this (commandText
, connection
, null)
81 Connection
= connection
;
84 public SybaseCommand (string commandText
, SybaseConnection connection
, SybaseTransaction transaction
)
86 this.commandText
= commandText
;
87 this.connection
= connection
;
88 this.transaction
= transaction
;
89 this.commandType
= CommandType
.Text
;
90 this.updatedRowSource
= UpdateRowSource
.Both
;
92 this.designTimeVisible
= false;
93 this.commandTimeout
= 30;
94 parameters
= new SybaseParameterCollection (this);
97 #endregion // Constructors
101 internal CommandBehavior CommandBehavior
{
102 get { return behavior; }
105 public string CommandText
{
106 get { return commandText; }
108 if (value != commandText
&& preparedStatement
!= null)
114 public int CommandTimeout
{
115 get { return commandTimeout; }
117 if (commandTimeout
< 0)
118 throw new ArgumentException ("The property value assigned is less than 0.");
119 commandTimeout
= value;
123 public CommandType CommandType
{
124 get { return commandType; }
126 if (value == CommandType
.TableDirect
)
127 throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono SybaseClient Data Provider.");
132 public SybaseConnection Connection
{
133 get { return connection; }
135 if (transaction
!= null && connection
.Transaction
!= null && connection
.Transaction
.IsOpen
)
136 throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress.");
142 public bool DesignTimeVisible
{
143 get { return designTimeVisible; }
144 set { designTimeVisible = value; }
147 public SybaseParameterCollection Parameters
{
148 get { return parameters; }
152 get { return Connection.Tds; }
155 IDbConnection IDbCommand
.Connection
{
156 get { return Connection; }
158 if (!(value is SybaseConnection
))
159 throw new InvalidCastException ("The value was not a valid SybaseConnection.");
160 Connection
= (SybaseConnection
) value;
164 IDataParameterCollection IDbCommand
.Parameters
{
165 get { return Parameters; }
168 IDbTransaction IDbCommand
.Transaction
{
169 get { return Transaction; }
171 if (!(value is SybaseTransaction
))
172 throw new ArgumentException ();
173 Transaction
= (SybaseTransaction
) value;
177 public SybaseTransaction Transaction
{
178 get { return transaction; }
179 set { transaction = value; }
182 public UpdateRowSource UpdatedRowSource
{
183 get { return updatedRowSource; }
184 set { updatedRowSource = value; }
191 public void Cancel ()
193 if (Connection
== null || Connection
.Tds
== null)
195 Connection
.Tds
.Cancel ();
198 internal void CloseDataReader (bool moreResults
)
200 GetOutputParameters ();
201 Connection
.DataReader
= null;
203 if ((behavior
& CommandBehavior
.CloseConnection
) != 0)
207 public SybaseParameter
CreateParameter ()
209 return new SybaseParameter ();
212 internal void DeriveParameters ()
214 if (commandType
!= CommandType
.StoredProcedure
)
215 throw new InvalidOperationException (String
.Format ("SybaseCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType
));
216 ValidateCommand ("DeriveParameters");
218 SybaseParameterCollection localParameters
= new SybaseParameterCollection (this);
219 localParameters
.Add ("@P1", SybaseType
.NVarChar
, commandText
.Length
).Value
= commandText
;
221 string sql
= "sp_procedure_params_rowset";
223 Connection
.Tds
.ExecProc (sql
, localParameters
.MetaParameters
, 0, true);
225 SybaseDataReader reader
= new SybaseDataReader (this);
227 object[] dbValues
= new object[reader
.FieldCount
];
229 while (reader
.Read ()) {
230 reader
.GetValues (dbValues
);
231 parameters
.Add (new SybaseParameter (dbValues
));
236 private void Execute (CommandBehavior behavior
, bool wantResults
)
238 TdsMetaParameterCollection parms
= Parameters
.MetaParameters
;
239 if (preparedStatement
== null) {
240 bool schemaOnly
= ((CommandBehavior
& CommandBehavior
.SchemaOnly
) > 0);
241 bool keyInfo
= ((CommandBehavior
& CommandBehavior
.SchemaOnly
) > 0);
243 StringBuilder sql1
= new StringBuilder ();
244 StringBuilder sql2
= new StringBuilder ();
246 if (schemaOnly
|| keyInfo
)
247 sql1
.Append ("SET FMTONLY OFF;");
249 sql1
.Append ("SET NO_BROWSETABLE ON;");
250 sql2
.Append ("SET NO_BROWSETABLE OFF;");
253 sql1
.Append ("SET FMTONLY ON;");
254 sql2
.Append ("SET FMTONLY OFF;");
257 switch (CommandType
) {
258 case CommandType
.StoredProcedure
:
259 if (keyInfo
|| schemaOnly
)
260 Connection
.Tds
.Execute (sql1
.ToString ());
261 Connection
.Tds
.ExecProc (CommandText
, parms
, CommandTimeout
, wantResults
);
262 if (keyInfo
|| schemaOnly
)
263 Connection
.Tds
.Execute (sql2
.ToString ());
265 case CommandType
.Text
:
266 string sql
= String
.Format ("{0}{1}{2}", sql1
.ToString (), CommandText
, sql2
.ToString ());
267 Connection
.Tds
.Execute (sql
, parms
, CommandTimeout
, wantResults
);
272 Connection
.Tds
.ExecPrepared (preparedStatement
, parms
, CommandTimeout
, wantResults
);
275 public int ExecuteNonQuery ()
277 ValidateCommand ("ExecuteNonQuery");
281 Execute (CommandBehavior
.Default
, false);
283 catch (TdsTimeoutException e
) {
284 throw SybaseException
.FromTdsInternalException ((TdsInternalException
) e
);
287 GetOutputParameters ();
291 public SybaseDataReader
ExecuteReader ()
293 return ExecuteReader (CommandBehavior
.Default
);
296 public SybaseDataReader
ExecuteReader (CommandBehavior behavior
)
298 ValidateCommand ("ExecuteReader");
300 Execute (behavior
, true);
302 catch (TdsTimeoutException e
) {
303 throw SybaseException
.FromTdsInternalException ((TdsInternalException
) e
);
305 Connection
.DataReader
= new SybaseDataReader (this);
306 return Connection
.DataReader
;
309 public object ExecuteScalar ()
311 ValidateCommand ("ExecuteScalar");
313 Execute (CommandBehavior
.Default
, true);
315 catch (TdsTimeoutException e
) {
316 throw SybaseException
.FromTdsInternalException ((TdsInternalException
) e
);
319 if (!Connection
.Tds
.NextResult () || !Connection
.Tds
.NextRow ())
322 object result
= Connection
.Tds
.ColumnValues
[0];
323 CloseDataReader (true);
327 private void GetOutputParameters ()
329 Connection
.Tds
.SkipToEnd ();
331 IList list
= Connection
.Tds
.ColumnValues
;
333 if (list
!= null && list
.Count
> 0) {
335 foreach (SybaseParameter parameter
in parameters
) {
336 if (parameter
.Direction
!= ParameterDirection
.Input
) {
337 parameter
.Value
= list
[index
];
340 if (index
>= list
.Count
)
346 object ICloneable
.Clone ()
348 return new SybaseCommand (commandText
, Connection
);
351 IDbDataParameter IDbCommand
.CreateParameter ()
353 return CreateParameter ();
356 IDataReader IDbCommand
.ExecuteReader ()
358 return ExecuteReader ();
361 IDataReader IDbCommand
.ExecuteReader (CommandBehavior behavior
)
363 return ExecuteReader (behavior
);
366 public void Prepare ()
368 ValidateCommand ("Prepare");
369 if (CommandType
== CommandType
.Text
)
370 preparedStatement
= Connection
.Tds
.Prepare (CommandText
, Parameters
.MetaParameters
);
373 public void ResetCommandTimeout ()
378 private void Unprepare ()
380 Connection
.Tds
.Unprepare (preparedStatement
);
381 preparedStatement
= null;
384 private void ValidateCommand (string method
)
386 if (Connection
== null)
387 throw new InvalidOperationException (String
.Format ("{0} requires a Connection object to continue.", method
));
388 if (Connection
.Transaction
!= null && transaction
!= Connection
.Transaction
)
389 throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object.");
390 if (Connection
.State
!= ConnectionState
.Open
)
391 throw new InvalidOperationException (String
.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method
));
392 if (commandText
== String
.Empty
|| commandText
== null)
393 throw new InvalidOperationException ("The command text for this Command has not been set.");
394 if (Connection
.DataReader
!= null)
395 throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
398 #endregion // Methods