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 using Mono.Data.Tds.Protocol;
17 using System.Collections;
18 using System.Collections.Specialized;
19 using System.ComponentModel;
21 using System.Data.Common;
22 using System.Runtime.InteropServices;
25 namespace Mono.Data.SybaseClient {
26 public sealed class SybaseCommand : Component, IDbCommand, ICloneable
30 bool disposed = false;
32 bool designTimeVisible;
34 CommandType commandType;
35 SybaseConnection connection;
36 SybaseTransaction transaction;
37 UpdateRowSource updatedRowSource;
38 CommandBehavior behavior = CommandBehavior.Default;
39 SybaseParameterCollection parameters;
40 string preparedStatement = null;
46 public SybaseCommand()
47 : this (String.Empty, null, null)
51 public SybaseCommand (string commandText)
52 : this (commandText, null, null)
54 commandText = commandText;
57 public SybaseCommand (string commandText, SybaseConnection connection)
58 : this (commandText, connection, null)
60 Connection = connection;
63 public SybaseCommand (string commandText, SybaseConnection connection, SybaseTransaction transaction)
65 this.commandText = commandText;
66 this.connection = connection;
67 this.transaction = transaction;
68 this.commandType = CommandType.Text;
69 this.updatedRowSource = UpdateRowSource.Both;
71 this.designTimeVisible = false;
72 this.commandTimeout = 30;
73 parameters = new SybaseParameterCollection (this);
76 #endregion // Constructors
80 internal CommandBehavior CommandBehavior {
81 get { return behavior; }
84 public string CommandText {
85 get { return commandText; }
87 if (value != commandText && preparedStatement != null)
93 public int CommandTimeout {
94 get { return commandTimeout; }
96 if (commandTimeout < 0)
97 throw new ArgumentException ("The property value assigned is less than 0.");
98 commandTimeout = value;
102 public CommandType CommandType {
103 get { return commandType; }
105 if (value == CommandType.TableDirect)
106 throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono SybaseClient Data Provider.");
111 public SybaseConnection Connection {
112 get { return connection; }
114 if (transaction != null && connection.Transaction != null && connection.Transaction.IsOpen)
115 throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress.");
121 public bool DesignTimeVisible {
122 get { return designTimeVisible; }
123 set { designTimeVisible = value; }
126 public SybaseParameterCollection Parameters {
127 get { return parameters; }
131 get { return Connection.Tds; }
134 IDbConnection IDbCommand.Connection {
135 get { return Connection; }
137 if (!(value is SybaseConnection))
138 throw new InvalidCastException ("The value was not a valid SybaseConnection.");
139 Connection = (SybaseConnection) value;
143 IDataParameterCollection IDbCommand.Parameters {
144 get { return Parameters; }
147 IDbTransaction IDbCommand.Transaction {
148 get { return Transaction; }
150 if (!(value is SybaseTransaction))
151 throw new ArgumentException ();
152 Transaction = (SybaseTransaction) value;
156 public SybaseTransaction Transaction {
157 get { return transaction; }
158 set { transaction = value; }
161 public UpdateRowSource UpdatedRowSource {
162 get { return updatedRowSource; }
163 set { updatedRowSource = value; }
170 public void Cancel ()
172 if (Connection == null || Connection.Tds == null)
174 Connection.Tds.Cancel ();
177 internal void CloseDataReader (bool moreResults)
179 GetOutputParameters ();
180 Connection.DataReader = null;
182 if ((behavior & CommandBehavior.CloseConnection) != 0)
186 public SybaseParameter CreateParameter ()
188 return new SybaseParameter ();
191 internal void DeriveParameters ()
193 if (commandType != CommandType.StoredProcedure)
194 throw new InvalidOperationException (String.Format ("SybaseCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
195 ValidateCommand ("DeriveParameters");
197 SybaseParameterCollection localParameters = new SybaseParameterCollection (this);
198 localParameters.Add ("@P1", SybaseType.NVarChar, commandText.Length).Value = commandText;
200 string sql = "sp_procedure_params_rowset";
202 Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true);
204 SybaseDataReader reader = new SybaseDataReader (this);
206 object[] dbValues = new object[reader.FieldCount];
208 while (reader.Read ()) {
209 reader.GetValues (dbValues);
210 parameters.Add (new SybaseParameter (dbValues));
215 private void Execute (CommandBehavior behavior, bool wantResults)
217 TdsMetaParameterCollection parms = Parameters.MetaParameters;
218 if (preparedStatement == null) {
219 bool schemaOnly = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
220 bool keyInfo = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
222 StringBuilder sql1 = new StringBuilder ();
223 StringBuilder sql2 = new StringBuilder ();
225 if (schemaOnly || keyInfo)
226 sql1.Append ("SET FMTONLY OFF;");
228 sql1.Append ("SET NO_BROWSETABLE ON;");
229 sql2.Append ("SET NO_BROWSETABLE OFF;");
232 sql1.Append ("SET FMTONLY ON;");
233 sql2.Append ("SET FMTONLY OFF;");
236 switch (CommandType) {
237 case CommandType.StoredProcedure:
238 if (keyInfo || schemaOnly)
239 Connection.Tds.Execute (sql1.ToString ());
240 Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults);
241 if (keyInfo || schemaOnly)
242 Connection.Tds.Execute (sql2.ToString ());
244 case CommandType.Text:
245 string sql = String.Format ("{0}{1}{2}", sql1.ToString (), CommandText, sql2.ToString ());
246 Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults);
251 Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
254 public int ExecuteNonQuery ()
256 ValidateCommand ("ExecuteNonQuery");
260 Execute (CommandBehavior.Default, false);
262 catch (TdsTimeoutException e) {
263 throw SybaseException.FromTdsInternalException ((TdsInternalException) e);
266 GetOutputParameters ();
270 public SybaseDataReader ExecuteReader ()
272 return ExecuteReader (CommandBehavior.Default);
275 public SybaseDataReader ExecuteReader (CommandBehavior behavior)
277 ValidateCommand ("ExecuteReader");
279 Execute (behavior, true);
281 catch (TdsTimeoutException e) {
282 throw SybaseException.FromTdsInternalException ((TdsInternalException) e);
284 Connection.DataReader = new SybaseDataReader (this);
285 return Connection.DataReader;
288 public object ExecuteScalar ()
290 ValidateCommand ("ExecuteScalar");
292 Execute (CommandBehavior.Default, true);
294 catch (TdsTimeoutException e) {
295 throw SybaseException.FromTdsInternalException ((TdsInternalException) e);
298 if (!Connection.Tds.NextResult () || !Connection.Tds.NextRow ())
301 object result = Connection.Tds.ColumnValues [0];
302 CloseDataReader (true);
306 private void GetOutputParameters ()
308 Connection.Tds.SkipToEnd ();
310 IList list = Connection.Tds.ColumnValues;
312 if (list != null && list.Count > 0) {
314 foreach (SybaseParameter parameter in parameters) {
315 if (parameter.Direction != ParameterDirection.Input) {
316 parameter.Value = list [index];
319 if (index >= list.Count)
325 object ICloneable.Clone ()
327 return new SybaseCommand (commandText, Connection);
330 IDbDataParameter IDbCommand.CreateParameter ()
332 return CreateParameter ();
335 IDataReader IDbCommand.ExecuteReader ()
337 return ExecuteReader ();
340 IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
342 return ExecuteReader (behavior);
345 public void Prepare ()
347 ValidateCommand ("Prepare");
348 if (CommandType == CommandType.Text)
349 preparedStatement = Connection.Tds.Prepare (CommandText, Parameters.MetaParameters);
352 public void ResetCommandTimeout ()
357 private void Unprepare ()
359 Connection.Tds.Unprepare (preparedStatement);
360 preparedStatement = null;
363 private void ValidateCommand (string method)
365 if (Connection == null)
366 throw new InvalidOperationException (String.Format ("{0} requires a Connection object to continue.", method));
367 if (Connection.Transaction != null && transaction != Connection.Transaction)
368 throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object.");
369 if (Connection.State != ConnectionState.Open)
370 throw new InvalidOperationException (String.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method));
371 if (commandText == String.Empty || commandText == null)
372 throw new InvalidOperationException ("The command text for this Command has not been set.");
373 if (Connection.DataReader != null)
374 throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
377 #endregion // Methods