4 // Part of the Mono class libraries at
5 // mcs/class/System.Data.OracleClient/System.Data.OracleClient
7 // Assembly: System.Data.OracleClient.dll
8 // Namespace: System.Data.OracleClient
11 // Daniel Morgan <danielmorgan@verizon.net>
12 // Tim Coleman <tim@timcoleman.com>
13 // Marek Safar <marek.safar@gmail.com>
15 // Copyright (C) Daniel Morgan, 2002, 2004-2005
16 // Copyright (C) Tim Coleman , 2003
18 // Licensed under the MIT/X11 License.
22 using System.ComponentModel;
24 using System.Data.Common;
25 using System.Data.OracleClient.Oci;
26 using System.Drawing.Design;
28 using System.Threading;
30 namespace System.Data.OracleClient
32 [DefaultEvent ("RecordsAffected")]
33 [Designer ("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + Consts.AssemblyMicrosoft_VSDesigner)]
35 public sealed class OracleCommand :
40 CommandBehavior behavior;
42 CommandType commandType;
43 OracleConnection connection;
44 bool designTimeVisible;
45 OracleParameterCollection parameters;
46 OracleTransaction transaction;
47 UpdateRowSource updatedRowSource;
48 OciStatementHandle preparedStatement;
56 public OracleCommand ()
57 : this (String.Empty, null, null)
61 public OracleCommand (string commandText)
62 : this (commandText, null, null)
66 public OracleCommand (string commandText, OracleConnection connection)
67 : this (commandText, connection, null)
71 public OracleCommand (string commandText, OracleConnection connection, OracleTransaction tx)
74 preparedStatement = null;
75 CommandText = commandText;
76 Connection = connection;
78 CommandType = CommandType.Text;
79 UpdatedRowSource = UpdateRowSource.Both;
80 DesignTimeVisible = true;
81 parameters = new OracleParameterCollection ();
84 #endregion // Constructors
89 [RefreshProperties (RefreshProperties.All)]
90 [Editor ("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
95 if (commandText == null)
100 set { commandText = value; }
103 [RefreshProperties (RefreshProperties.All)]
104 [DefaultValue (CommandType.Text)]
107 CommandType CommandType {
108 get { return commandType; }
110 if (value == CommandType.TableDirect)
111 throw new ArgumentException ("OracleClient provider does not support TableDirect CommandType.");
116 [DefaultValue (null)]
117 [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
120 OracleConnection Connection {
121 get { return connection; }
122 set { connection = value; }
126 [EditorBrowsable (EditorBrowsableState.Never)]
127 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
128 public override int CommandTimeout {
134 protected override DbConnection DbConnection {
135 get { return Connection; }
136 set { Connection = (OracleConnection) value; }
140 protected override DbParameterCollection DbParameterCollection {
141 get { return Parameters; }
145 protected override DbTransaction DbTransaction {
146 get { return Transaction; }
147 set { Transaction = (OracleTransaction) value; }
150 [DefaultValue (true)]
153 [EditorBrowsable (EditorBrowsableState.Never)]
156 bool DesignTimeVisible {
157 get { return designTimeVisible; }
158 set { designTimeVisible = value; }
161 internal OciEnvironmentHandle Environment {
162 get { return Connection.Environment; }
165 internal OciErrorHandle ErrorHandle {
166 get { return Connection.ErrorHandle; }
170 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
173 OracleParameterCollection Parameters {
174 get { return parameters; }
178 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
181 OracleTransaction Transaction {
182 get { return transaction; }
183 set { transaction = value; }
186 [DefaultValue (UpdateRowSource.Both)]
189 UpdateRowSource UpdatedRowSource {
190 get { return updatedRowSource; }
191 set { updatedRowSource = value; }
198 private void AssertCommandTextIsSet ()
200 if (CommandText.Length == 0)
201 throw new InvalidOperationException ("The command text for this Command has not been set.");
204 private void AssertConnectionIsOpen ()
206 if (Connection == null || Connection.State == ConnectionState.Closed)
207 throw new InvalidOperationException ("An open Connection object is required to continue.");
210 private void AssertTransactionMatch ()
212 if (Connection.Transaction != null && Transaction != Connection.Transaction)
213 throw new InvalidOperationException ("Execute requires the Command object to have a Transaction object when the Connection object assigned to the command is in a pending local transaction. The Transaction property of the Command has not been initialized.");
216 private void BindParameters (OciStatementHandle statement)
218 for (int p = 0; p < Parameters.Count; p++)
219 Parameters[p].Bind (statement, Connection, (uint) p);
227 throw new NotImplementedException ();
231 public object Clone ()
233 // create a new OracleCommand object with the same properties
235 OracleCommand cmd = new OracleCommand ();
237 cmd.CommandText = this.CommandText;
238 cmd.CommandType = this.CommandType;
240 // FIXME: not sure if I should set the same object here
241 // or get a clone of these too
242 cmd.Connection = this.Connection;
243 cmd.Transaction = this.Transaction;
245 foreach (OracleParameter parm in this.Parameters) {
247 OracleParameter newParm = cmd.CreateParameter ();
249 newParm.DbType = parm.DbType;
250 newParm.Direction = parm.Direction;
251 newParm.IsNullable = parm.IsNullable;
252 newParm.Offset = parm.Offset;
253 newParm.OracleType = parm.OracleType;
254 newParm.ParameterName = parm.ParameterName;
255 //newParm.Precision = parm.Precision;
256 //newParm.Scale = parm.Scale;
257 newParm.SourceColumn = parm.SourceColumn;
258 newParm.SourceVersion = parm.SourceVersion;
259 newParm.Value = parm.Value;
261 cmd.Parameters.Add (newParm);
264 //cmd.Container = this.Container;
265 cmd.DesignTimeVisible = this.DesignTimeVisible;
266 //cmd.DesignMode = this.DesignMode;
267 cmd.Site = this.Site;
268 //cmd.UpdateRowSource = this.UpdateRowSource;
273 protected override DbParameter CreateDbParameter ()
275 return CreateParameter ();
278 protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
280 return ExecuteReader (behavior);
283 internal void UpdateParameterValues ()
286 if (Parameters.Count > 0) {
287 bool foundCursor = false;
288 for (int p = 0; p < Parameters.Count; p++) {
289 OracleParameter parm = Parameters [p];
290 if (parm.OracleType.Equals (OracleType.Cursor)) {
291 if (!foundCursor && parm.Direction != ParameterDirection.Input) {
292 // if there are multiple REF CURSORs,
293 // you only can get the first cursor for now
294 // because user of OracleDataReader
295 // will do a NextResult to get the next
296 // REF CURSOR (if it exists)
299 if (p + 1 == Parameters.Count)
310 internal void CloseDataReader ()
312 Connection.DataReader = null;
313 if ((behavior & CommandBehavior.CloseConnection) != 0)
319 OracleParameter CreateParameter ()
321 return new OracleParameter ();
324 internal void DeriveParameters ()
326 if (commandType != CommandType.StoredProcedure)
327 throw new InvalidOperationException (String.Format ("OracleCommandBuilder DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
329 //OracleParameterCollection localParameters = new OracleParameterCollection (this);
331 throw new NotImplementedException ();
334 private int ExecuteNonQueryInternal (OciStatementHandle statement, bool useAutoCommit)
338 if (preparedStatement == null)
339 PrepareStatement (statement);
341 bool isNonQuery = IsNonQuery (statement);
343 BindParameters (statement);
344 if (isNonQuery == true)
345 statement.ExecuteNonQuery (useAutoCommit);
347 statement.ExecuteQuery (false);
349 UpdateParameterValues ();
351 int rowsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, ErrorHandle);
358 int ExecuteNonQuery ()
362 AssertConnectionIsOpen ();
363 AssertTransactionMatch ();
364 AssertCommandTextIsSet ();
365 bool useAutoCommit = false;
367 if (Transaction != null)
368 Transaction.AttachToServiceContext ();
370 useAutoCommit = true;
372 OciStatementHandle statement = GetStatementHandle ();
374 return ExecuteNonQueryInternal (statement, useAutoCommit);
376 SafeDisposeHandle (statement);
380 public int ExecuteOracleNonQuery (out OracleString rowid)
384 AssertConnectionIsOpen ();
385 AssertTransactionMatch ();
386 AssertCommandTextIsSet ();
387 bool useAutoCommit = false;
389 if (Transaction != null)
390 Transaction.AttachToServiceContext ();
392 useAutoCommit = true;
394 OciStatementHandle statement = GetStatementHandle ();
397 int retval = ExecuteNonQueryInternal (statement, useAutoCommit);
398 OciRowIdDescriptor rowIdDescriptor = statement.GetAttributeRowIdDescriptor (ErrorHandle, Environment);
399 string srowid = rowIdDescriptor.GetRowIdToString (ErrorHandle);
400 rowid = new OracleString (srowid);
401 rowIdDescriptor = null;
404 SafeDisposeHandle (statement);
408 public object ExecuteOracleScalar ()
412 object output = DBNull.Value;
414 AssertConnectionIsOpen ();
415 AssertTransactionMatch ();
416 AssertCommandTextIsSet ();
418 if (Transaction != null)
419 Transaction.AttachToServiceContext ();
421 OciStatementHandle statement = GetStatementHandle ();
423 if (preparedStatement == null)
424 PrepareStatement (statement);
426 bool isNonQuery = IsNonQuery (statement);
428 BindParameters (statement);
430 if (isNonQuery == true)
431 ExecuteNonQueryInternal (statement, false);
433 statement.ExecuteQuery (false);
435 if (statement.Fetch ()) {
436 OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
437 if (!defineHandle.IsNull)
438 output = defineHandle.GetOracleValue (Connection.SessionFormatProvider, Connection);
439 switch (defineHandle.DataType) {
440 case OciDataType.Blob:
441 case OciDataType.Clob:
442 ((OracleLob) output).connection = Connection;
446 UpdateParameterValues ();
451 SafeDisposeHandle (statement);
455 private bool IsNonQuery (OciStatementHandle statementHandle)
457 // assumes Prepare() has been called prior to calling this function
459 OciStatementType statementType = statementHandle.GetStatementType ();
460 if (statementType.Equals (OciStatementType.Select))
468 OracleDataReader ExecuteReader ()
470 return ExecuteReader (CommandBehavior.Default);
475 OracleDataReader ExecuteReader (CommandBehavior behavior)
477 AssertConnectionIsOpen ();
478 AssertTransactionMatch ();
479 AssertCommandTextIsSet ();
483 bool hasRows = false;
485 this.behavior = behavior;
487 if (Transaction != null)
488 Transaction.AttachToServiceContext ();
490 OciStatementHandle statement = GetStatementHandle ();
491 OracleDataReader rd = null;
494 if (preparedStatement == null)
495 PrepareStatement (statement);
497 preparedStatement = null; // OracleDataReader releases the statement handle
499 bool isNonQuery = IsNonQuery (statement);
501 BindParameters (statement);
504 ExecuteNonQueryInternal (statement, false);
506 if ((behavior & CommandBehavior.SchemaOnly) != 0)
507 statement.ExecuteQuery (true);
509 hasRows = statement.ExecuteQuery (false);
511 UpdateParameterValues ();
514 if (Parameters.Count > 0) {
515 for (int p = 0; p < Parameters.Count; p++) {
516 OracleParameter parm = Parameters [p];
517 if (parm.OracleType.Equals (OracleType.Cursor)) {
518 if (parm.Direction != ParameterDirection.Input) {
519 rd = (OracleDataReader) parm.Value;
527 rd = new OracleDataReader (this, statement, hasRows, behavior);
530 if (statement != null && rd == null)
539 object ExecuteScalar ()
542 object output = null;//if we find nothing we return this
544 AssertConnectionIsOpen ();
545 AssertTransactionMatch ();
546 AssertCommandTextIsSet ();
548 if (Transaction != null)
549 Transaction.AttachToServiceContext ();
551 OciStatementHandle statement = GetStatementHandle ();
553 if (preparedStatement == null)
554 PrepareStatement (statement);
556 bool isNonQuery = IsNonQuery (statement);
558 BindParameters (statement);
560 if (isNonQuery == true)
561 ExecuteNonQueryInternal (statement, false);
563 statement.ExecuteQuery (false);
565 if (statement.Fetch ()) {
566 OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
567 if (!defineHandle.IsNull)
569 switch (defineHandle.DataType) {
570 case OciDataType.Blob:
571 case OciDataType.Clob:
572 OracleLob lob = (OracleLob) defineHandle.GetValue (
573 Connection.SessionFormatProvider, Connection);
574 lob.connection = Connection;
579 output = defineHandle.GetValue (
580 Connection.SessionFormatProvider, Connection);
585 UpdateParameterValues ();
588 SafeDisposeHandle (statement);
594 internal OciStatementHandle GetNextResult ()
596 if (moreResults == -1)
599 if (Parameters.Count > 0) {
600 int p = moreResults + 1;
602 if (p >= Parameters.Count) {
607 for (; p < Parameters.Count; p++) {
608 OracleParameter parm = Parameters [p];
609 if (parm.OracleType.Equals (OracleType.Cursor)) {
610 if (parm.Direction != ParameterDirection.Input) {
611 if (p + 1 == Parameters.Count)
615 return parm.GetOutRefCursor (this);
626 private OciStatementHandle GetStatementHandle ()
628 AssertConnectionIsOpen ();
629 if (preparedStatement != null)
630 return preparedStatement;
632 OciStatementHandle h = (OciStatementHandle) Connection.Environment.Allocate (OciHandleType.Statement);
633 h.ErrorHandle = Connection.ErrorHandle;
634 h.Service = Connection.ServiceContext;
639 private void SafeDisposeHandle (OciStatementHandle h)
641 if (h != null && h != preparedStatement)
646 void PrepareStatement (OciStatementHandle statement)
648 if (commandType == CommandType.StoredProcedure) {
649 StringBuilder sb = new StringBuilder ();
650 if (Parameters.Count > 0)
651 foreach (OracleParameter parm in Parameters) {
654 sb.Append (parm.ParameterName + "=>:" + parm.ParameterName);
657 string sql = "begin " + commandText + "(" + sb.ToString() + "); end;";
658 statement.Prepare (sql);
660 statement.Prepare (commandText);
667 AssertConnectionIsOpen ();
668 OciStatementHandle statement = GetStatementHandle ();
669 PrepareStatement (statement);
670 preparedStatement = statement;
673 protected override void Dispose (bool disposing)
675 if (preparedStatement != null)
676 OciCalls.OCIHandleFree(preparedStatement,
677 OciHandleType.Statement);
679 if (Parameters.Count > 0)
680 foreach (OracleParameter parm in Parameters)
682 base.Dispose (disposing);
685 #endregion // Methods