3 using System.Runtime.InteropServices;
9 public class DB2Command : System.ComponentModel.Component,IDbCommand
11 #region Private data members
14 private WeakReference refDataReader;
15 private string commandText;
16 private CommandType commandType = CommandType.Text;
17 private DB2Connection db2Conn;
18 private DB2Transaction db2Trans;
19 private int commandTimeout;
20 private bool prepared = false;
21 private IntPtr hwndStmt = IntPtr.Zero; //Our statement handle
22 private DB2ParameterCollection parameters = new DB2ParameterCollection();
23 private bool disposed = false;
24 private bool statementOpen;
33 hwndStmt = IntPtr.Zero;
35 public DB2Command(string commandStr):this()
37 commandText = commandStr;
40 public DB2Command(string commandStr, DB2Connection con) : this(commandStr)
43 AllocateStatement("Constructor 3");
45 public DB2Command (string commandStr, DB2Connection con, DB2Transaction trans):this(commandStr, con)
52 AllocateStatement("Constructor 4");
57 public new void Dispose()
60 GC.SuppressFinalize(this);
63 protected override void Dispose(bool disposing)
72 db2Conn.RemoveCommand(this);
77 base.Dispose(disposing);
87 internal void DataReaderClosed()
89 CloseStatementHandle(false);
93 private void CloseStatementHandle(bool dispose)
95 if(hwndStmt != IntPtr.Zero)
99 short sqlRet = DB2CLIWrapper.SQLFreeStmt(hwndStmt, DB2Constants.SQL_CLOSE);
100 Db2Environment.Log("Close stm {0,-4} {1}", hwndStmt, sqlRet);
102 if((!prepared && statementOpen) ||
105 short sqlRet = DB2CLIWrapper.SQLFreeHandle(DB2Constants.SQL_HANDLE_STMT, hwndStmt);
107 hwndStmt = IntPtr.Zero;
110 statementOpen = false;
114 internal void ConnectionClosed()
116 DB2DataReader reader = null;
117 if((refDataReader != null) && refDataReader.IsAlive)
119 reader = (DB2DataReader)refDataReader.Target;
121 if((reader != null) && refDataReader.IsAlive)
124 refDataReader = null;
126 CloseStatementHandle(true);
133 #region SelfDescribe property
135 /// Property dictates whether or not any paramter markers will get their describe info
136 /// from the database, or if the user will supply the information
138 bool selfDescribe = false;
139 public bool SelfDescribe
147 selfDescribe = value;
152 #region CommandText property
154 ///The query; If it gets set, reset the prepared property
156 public string CommandText
170 #region CommandTimeout property
172 /// The Timeout property states how long we wait for results to return
174 public int CommandTimeout
178 return commandTimeout;
182 commandTimeout = value;
187 #region CommandType property
189 public CommandType CommandType
202 #region Connection property
204 /// The connection we'll be executing on.
206 IDbConnection IDbCommand.Connection
214 db2Conn = (DB2Connection)value;
215 //AllocateStatement("Connection property set");
219 public DB2Connection Connection
229 db2Conn.RemoveCommand(this);
234 db2Conn.AddCommand(this);
240 #region Parameters property
242 /// Parameter list, Not yet implemented
244 public DB2ParameterCollection Parameters
251 IDataParameterCollection IDbCommand.Parameters
260 #region Transaction property
262 /// The transaction this command is associated with
264 public IDbTransaction Transaction
272 db2Trans = (DB2Transaction)value;
277 #region UpdatedRowSource property
279 public UpdateRowSource UpdatedRowSource
283 throw new DB2Exception ("TBD");
287 throw new DB2Exception ("TBD");
292 #region Statement Handle
294 /// returns the DB2Client statement handle
296 public IntPtr statementHandle
305 #region AllocateStatement function
307 internal void AllocateStatement(string location)
309 if (db2Conn.DBHandle.ToInt32() == 0) return;
311 sqlRet = DB2CLIWrapper.SQLAllocHandle(DB2Constants.SQL_HANDLE_STMT, db2Conn.DBHandle , ref hwndStmt);
312 Console.WriteLine("Connection handle : {0}", db2Conn.DBHandle.ToInt32().ToString());
313 Db2Environment.Log("Alloc stm {0,-4} {1}", hwndStmt, sqlRet);
314 if ((sqlRet != DB2Constants.SQL_SUCCESS) && (sqlRet != DB2Constants.SQL_SUCCESS_WITH_INFO))
315 throw new DB2Exception(DB2Constants.SQL_HANDLE_DBC, db2Conn.DBHandle, location +": Unable to allocate statement handle.");
316 parameters.HwndStmt = hwndStmt;
322 /// Attempt to cancel an executing command
326 if(hwndStmt == IntPtr.Zero)
328 throw new InvalidOperationException("Nothing to Cancel.");
330 DB2CLIWrapper.SQLCancel(hwndStmt);
334 #region CreateParameter
336 ///Returns a parameter
338 public IDbDataParameter CreateParameter()
340 throw new DB2Exception("TBD");
344 #region ExecuteNonQuery
346 public int ExecuteNonQuery()
348 int result = ExecuteNonQueryInternal();
349 CloseStatementHandle(false);
354 public int ExecuteNonQueryInternal()
356 if((db2Conn == null) || (db2Conn.State != ConnectionState.Open))
357 throw new InvalidOperationException("Prepare needs an open connection");
359 if (hwndStmt == IntPtr.Zero)
361 AllocateStatement("InternalExecuteNonQuery");
363 if ((commandText == null) ||(commandText.Length == 0))
364 throw new InvalidOperationException("Command string is empty");
366 if(CommandType.StoredProcedure == commandType && !commandText.StartsWith("CALL "))
367 commandText = "CALL " + commandText;
372 sqlRet = DB2CLIWrapper.SQLExecute(hwndStmt);
373 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "SQLExecute error.");
377 sqlRet = DB2CLIWrapper.SQLExecDirect(hwndStmt, commandText, commandText.Length);
378 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "SQLExecDirect error.");
380 statementOpen = true;
383 sqlRet = DB2CLIWrapper.SQLRowCount(hwndStmt, ref numRows); //How many rows affected. numRows will be -1 if we aren't dealing with an Insert, Delete or Update, or if the statement did not execute successfully
384 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "SQLExecDirect error.");
387 parameters.GetOutValues();
388 ///At this point, I think we need to save any results, but not return them
389 ///For now, we will go execute and return the number of rows affected
394 #region ExecuteReader calls
398 IDataReader IDbCommand.ExecuteReader()
400 return ExecuteReader(0);
403 IDataReader IDbCommand.ExecuteReader(CommandBehavior behavior)
405 return ExecuteReader(behavior);
408 public DB2DataReader ExecuteReader()
410 return ExecuteReader(0);
413 public DB2DataReader ExecuteReader(CommandBehavior behavior)
415 if((db2Conn == null) || (db2Conn.State != ConnectionState.Open))
416 throw new InvalidOperationException("Prepare needs an open connection");
418 DB2DataReader reader;
420 int nrOfRows = ExecuteNonQueryInternal();
422 reader = new DB2DataReader(db2Conn, this);
423 reader.recordsAffected = nrOfRows;
425 refDataReader = new WeakReference(reader);
431 #region ExecuteScalar
435 public object ExecuteScalar()
437 if((db2Conn == null) || (db2Conn.State != ConnectionState.Open))
438 throw new InvalidOperationException("Prepare needs an open connection");
440 using(DB2DataReader reader = ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.SingleRow))
442 if(reader.Read() && (reader.FieldCount > 0))
453 public void Prepare ()
455 if((db2Conn == null) || (db2Conn.State != ConnectionState.Open))
456 throw new InvalidOperationException("Prepare needs an open connection");
458 CloseStatementHandle(false);
459 if (hwndStmt == IntPtr.Zero)
461 AllocateStatement("InternalExecuteNonQuery");
466 IntPtr numParams = IntPtr.Zero;
467 sqlRet = DB2CLIWrapper.SQLPrepare(hwndStmt, commandText, commandText.Length);
468 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "SQLPrepare error.");
470 statementOpen = true;
473 foreach ( DB2Parameter param in parameters)
478 sqlRet = param.Describe(this.hwndStmt, i);
479 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "Error binding parameter in Db2Command: ");
481 sqlRet = param.Bind(this.hwndStmt, i);
482 DB2ClientUtils.DB2CheckReturn(sqlRet, DB2Constants.SQL_HANDLE_STMT, hwndStmt, "Error binding parameter in Db2Command: ");