2 // System.Data.Odbc.OdbcCommand
5 // Brian Ritchie (brianlritchie@hotmail.com)
7 // Copyright (C) Brian Ritchie, 2002
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.ComponentModel;
36 using System.Data.Common;
37 using System.Collections;
38 using System.Runtime.InteropServices;
40 namespace System.Data.Odbc
43 /// Represents an SQL statement or stored procedure to execute against a data source.
45 [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.OdbcCommandDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
46 [ToolboxItemAttribute ("System.Drawing.Design.ToolboxItem, "+ Consts.AssemblySystem_Drawing)]
48 public sealed class OdbcCommand : DbCommand, ICloneable
50 public sealed class OdbcCommand : Component, ICloneable, IDbCommand
57 CommandType commandType;
58 UpdateRowSource updateRowSource = UpdateRowSource.Both;
60 OdbcConnection connection;
61 OdbcTransaction transaction;
62 OdbcParameterCollection _parameters;
64 bool designTimeVisible;
66 IntPtr hstmt = IntPtr.Zero;
68 bool disposed = false;
76 this.CommandText = String.Empty;
77 this.CommandTimeout = 30; // default timeout
78 this.CommandType = CommandType.Text;
80 _parameters = new OdbcParameterCollection ();
82 designTimeVisible = false;
84 updateRowSource = UpdateRowSource.Both;
88 public OdbcCommand (string cmdText) : this ()
90 CommandText = cmdText;
93 public OdbcCommand (string cmdText, OdbcConnection connection)
96 Connection = connection;
99 public OdbcCommand (string cmdText,
100 OdbcConnection connection,
101 OdbcTransaction transaction) : this (cmdText, connection)
103 this.Transaction = transaction;
106 #endregion // Constructors
110 internal IntPtr hStmt
112 get { return hstmt; }
116 [OdbcCategory ("Data")]
118 [OdbcDescriptionAttribute ("Command text to execute")]
119 [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
120 [RefreshPropertiesAttribute (RefreshProperties.All)]
127 get { return commandText; }
134 [OdbcDescriptionAttribute ("Time to wait for command to execute")]
141 get { return timeout; }
142 set { timeout = value; }
145 [OdbcCategory ("Data")]
146 [DefaultValue ("Text")]
147 [OdbcDescriptionAttribute ("How to interpret the CommandText")]
148 [RefreshPropertiesAttribute (RefreshProperties.All)]
153 CommandType CommandType {
154 get { return commandType; }
155 set { commandType = value; }
159 [OdbcCategory ("Behavior")]
160 [OdbcDescriptionAttribute ("Connection used by the command")]
161 [DefaultValue (null)]
162 [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
163 public OdbcConnection Connection {
174 public new OdbcConnection Connection
176 get { return DbConnection as OdbcConnection; }
177 set { DbConnection = value; }
182 [BrowsableAttribute (false)]
183 [DesignOnlyAttribute (true)]
184 [DefaultValue (true)]
189 bool DesignTimeVisible {
191 return designTimeVisible;
194 designTimeVisible = value;
199 [OdbcCategory ("Data")]
200 [OdbcDescriptionAttribute ("The parameters collection")]
201 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
206 OdbcParameterCollection Parameters {
211 return base.Parameters as OdbcParameterCollection;
217 [BrowsableAttribute (false)]
218 [OdbcDescriptionAttribute ("The transaction used by the command")]
219 [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
224 OdbcTransaction Transaction {
233 [OdbcCategory ("Behavior")]
234 [DefaultValue (UpdateRowSource.Both)]
235 [OdbcDescriptionAttribute ("When used by a DataAdapter.Update, how command results are applied to the current DataRow")]
240 UpdateRowSource UpdatedRowSource {
243 return updateRowSource;
247 updateRowSource = value;
252 protected override DbConnection DbConnection
254 get { return connection; }
256 connection = (OdbcConnection) value;
264 IDbConnection IDbCommand.Connection {
269 Connection = (OdbcConnection) value;
273 IDataParameterCollection IDbCommand.Parameters {
279 protected override DbParameterCollection DbParameterCollection
281 get { return _parameters as DbParameterCollection;}
287 IDbTransaction IDbCommand.Transaction {
289 return (IDbTransaction) Transaction;
292 if (value is OdbcTransaction)
294 Transaction = (OdbcTransaction)value;
298 throw new ArgumentException ();
303 protected override DbTransaction DbTransaction
305 get { return transaction; }
307 transaction = (OdbcTransaction)value;
314 #endregion // Properties
324 if (hstmt!=IntPtr.Zero)
326 OdbcReturn Ret=libodbc.SQLCancel(hstmt);
327 if ((Ret!=OdbcReturn.Success) && (Ret!=OdbcReturn.SuccessWithInfo))
328 throw new OdbcException(new OdbcError("SQLCancel",OdbcHandleType.Stmt,hstmt));
331 throw new InvalidOperationException();
335 IDbDataParameter IDbCommand.CreateParameter ()
337 return CreateParameter ();
341 protected override DbParameter CreateDbParameter ()
343 return CreateParameter ();
348 public new OdbcParameter CreateParameter ()
350 return new OdbcParameter ();
353 protected override void Dispose (bool disposing)
358 FreeStatement (); // free handles
364 private IntPtr ReAllocStatment ()
368 if (hstmt != IntPtr.Zero)
371 ret=libodbc.SQLAllocHandle(OdbcHandleType.Stmt, Connection.hDbc, ref hstmt);
372 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
373 throw new OdbcException(new OdbcError("SQLAllocHandle",OdbcHandleType.Dbc,Connection.hDbc));
378 private void FreeStatement ()
380 if (hstmt == IntPtr.Zero)
383 // free previously allocated handle.
384 OdbcReturn ret = libodbc.SQLFreeStmt (hstmt, libodbc.SQLFreeStmtOptions.Close);
385 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
386 throw new OdbcException(new OdbcError("SQLCloseCursor",OdbcHandleType.Stmt,hstmt));
388 ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, hstmt);
389 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
390 throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,hstmt));
394 private void ExecSQL(string sql)
397 if (! prepared && Parameters.Count <= 0) {
401 ret=libodbc.SQLExecDirect(hstmt, sql, sql.Length);
402 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
403 throw new OdbcException(new OdbcError("SQLExecDirect",OdbcHandleType.Stmt,hstmt));
411 ret=libodbc.SQLExecute(hstmt);
412 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
413 throw new OdbcException(new OdbcError("SQLExecute",OdbcHandleType.Stmt,hstmt));
416 internal void FreeIfNotPrepared ()
426 int ExecuteNonQuery ()
428 return ExecuteNonQuery (true);
431 private int ExecuteNonQuery (bool freeHandle)
434 if (Connection == null)
435 throw new InvalidOperationException ();
436 if (Connection.State == ConnectionState.Closed)
437 throw new InvalidOperationException ();
438 // FIXME: a third check is mentioned in .NET docs
440 ExecSQL(CommandText);
442 // .NET documentation says that except for INSERT, UPDATE and
443 // DELETE where the return value is the number of rows affected
444 // for the rest of the commands the return value is -1.
445 if ((CommandText.ToUpper().IndexOf("UPDATE")!=-1) ||
446 (CommandText.ToUpper().IndexOf("INSERT")!=-1) ||
447 (CommandText.ToUpper().IndexOf("DELETE")!=-1)) {
450 OdbcReturn ret = libodbc.SQLRowCount(hstmt,ref numrows);
456 if (freeHandle && !prepared)
471 ret=libodbc.SQLPrepare(hstmt, CommandText, CommandText.Length);
472 if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
473 throw new OdbcException(new OdbcError("SQLPrepare",OdbcHandleType.Stmt,hstmt));
477 private void BindParameters ()
480 foreach (OdbcParameter p in Parameters)
493 OdbcDataReader ExecuteReader ()
495 return ExecuteReader (CommandBehavior.Default);
499 IDataReader IDbCommand.ExecuteReader ()
501 return ExecuteReader ();
504 protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
506 return ExecuteReader (behavior);
515 OdbcDataReader ExecuteReader (CommandBehavior behavior)
517 int recordsAffected = ExecuteNonQuery(false);
518 OdbcDataReader dataReader=new OdbcDataReader(this, behavior, recordsAffected);
523 IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
525 return ExecuteReader (behavior);
533 object ExecuteScalar ()
536 OdbcDataReader reader=ExecuteReader();
550 object ICloneable.Clone ()
552 throw new NotImplementedException ();
555 public void ResetCommandTimeout ()