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;
25 using System.Data.Common;
27 using System.Data.OracleClient.Oci;
28 using System.Drawing.Design;
31 namespace System.Data.OracleClient
34 [DefaultEvent ("RecordsAffected")]
36 [Designer ("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + Consts.AssemblyMicrosoft_VSDesigner)]
38 public sealed class OracleCommand :
42 Component, ICloneable, IDbCommand
47 CommandBehavior behavior;
49 CommandType commandType;
50 OracleConnection connection;
51 bool designTimeVisible;
52 OracleParameterCollection parameters;
53 OracleTransaction transaction;
54 UpdateRowSource updatedRowSource;
55 OciStatementHandle preparedStatement;
63 public OracleCommand ()
64 : this (String.Empty, null, null)
68 public OracleCommand (string commandText)
69 : this (commandText, null, null)
73 public OracleCommand (string commandText, OracleConnection connection)
74 : this (commandText, connection, null)
78 public OracleCommand (string commandText, OracleConnection connection, OracleTransaction tx)
81 preparedStatement = null;
82 CommandText = commandText;
83 Connection = connection;
85 CommandType = CommandType.Text;
86 UpdatedRowSource = UpdateRowSource.Both;
87 DesignTimeVisible = true;
88 parameters = new OracleParameterCollection ();
91 #endregion // Constructors
96 [RefreshProperties (RefreshProperties.All)]
97 [Editor ("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
104 if (commandText == null)
109 set { commandText = value; }
112 [RefreshProperties (RefreshProperties.All)]
113 [DefaultValue (CommandType.Text)]
118 CommandType CommandType {
119 get { return commandType; }
121 if (value == CommandType.TableDirect)
122 throw new ArgumentException ("OracleClient provider does not support TableDirect CommandType.");
127 [DefaultValue (null)]
128 [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
133 OracleConnection Connection {
134 get { return connection; }
135 set { connection = value; }
140 [EditorBrowsable (EditorBrowsableState.Never)]
141 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
142 public override int CommandTimeout {
148 protected override DbConnection DbConnection {
149 get { return Connection; }
150 set { Connection = (OracleConnection) value; }
154 protected override DbParameterCollection DbParameterCollection {
155 get { return Parameters; }
159 protected override DbTransaction DbTransaction {
160 get { return Transaction; }
161 set { Transaction = (OracleTransaction) value; }
165 [DefaultValue (true)]
169 [EditorBrowsable (EditorBrowsableState.Never)]
175 bool DesignTimeVisible {
176 get { return designTimeVisible; }
177 set { designTimeVisible = value; }
180 internal OciEnvironmentHandle Environment {
181 get { return Connection.Environment; }
184 internal OciErrorHandle ErrorHandle {
185 get { return Connection.ErrorHandle; }
189 int IDbCommand.CommandTimeout {
194 [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
195 [DefaultValue (null)]
196 IDbConnection IDbCommand.Connection {
197 get { return Connection; }
199 // InvalidCastException is expected when types do not match
200 Connection = (OracleConnection) value;
204 IDataParameterCollection IDbCommand.Parameters {
205 get { return Parameters; }
208 IDbTransaction IDbCommand.Transaction {
209 get { return Transaction; }
211 // InvalidCastException is expected when types do not match
212 Transaction = (OracleTransaction) value;
217 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
222 OracleParameterCollection Parameters {
223 get { return parameters; }
227 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
232 OracleTransaction Transaction {
233 get { return transaction; }
234 set { transaction = value; }
237 [DefaultValue (UpdateRowSource.Both)]
242 UpdateRowSource UpdatedRowSource {
243 get { return updatedRowSource; }
244 set { updatedRowSource = value; }
251 private void AssertCommandTextIsSet ()
253 if (CommandText.Length == 0)
254 throw new InvalidOperationException ("The command text for this Command has not been set.");
257 private void AssertConnectionIsOpen ()
259 if (Connection == null || Connection.State == ConnectionState.Closed)
260 throw new InvalidOperationException ("An open Connection object is required to continue.");
263 private void AssertTransactionMatch ()
265 if (Connection.Transaction != null && Transaction != Connection.Transaction)
266 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.");
269 private void BindParameters (OciStatementHandle statement)
271 for (int p = 0; p < Parameters.Count; p++)
272 Parameters[p].Bind (statement, Connection, (uint) p);
282 throw new NotImplementedException ();
286 public object Clone ()
288 // create a new OracleCommand object with the same properties
290 OracleCommand cmd = new OracleCommand ();
292 cmd.CommandText = this.CommandText;
293 cmd.CommandType = this.CommandType;
295 // FIXME: not sure if I should set the same object here
296 // or get a clone of these too
297 cmd.Connection = this.Connection;
298 cmd.Transaction = this.Transaction;
300 foreach (OracleParameter parm in this.Parameters) {
302 OracleParameter newParm = cmd.CreateParameter ();
304 newParm.DbType = parm.DbType;
305 newParm.Direction = parm.Direction;
306 newParm.IsNullable = parm.IsNullable;
307 newParm.Offset = parm.Offset;
308 newParm.OracleType = parm.OracleType;
309 newParm.ParameterName = parm.ParameterName;
310 //newParm.Precision = parm.Precision;
311 //newParm.Scale = parm.Scale;
312 newParm.SourceColumn = parm.SourceColumn;
313 newParm.SourceVersion = parm.SourceVersion;
314 newParm.Value = parm.Value;
316 cmd.Parameters.Add (newParm);
319 //cmd.Container = this.Container;
320 cmd.DesignTimeVisible = this.DesignTimeVisible;
321 //cmd.DesignMode = this.DesignMode;
322 cmd.Site = this.Site;
323 //cmd.UpdateRowSource = this.UpdateRowSource;
329 protected override DbParameter CreateDbParameter ()
331 return CreateParameter ();
334 protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
336 return ExecuteReader (behavior);
340 internal void UpdateParameterValues ()
343 if (Parameters.Count > 0) {
344 bool foundCursor = false;
345 for (int p = 0; p < Parameters.Count; p++) {
346 OracleParameter parm = Parameters [p];
347 if (parm.OracleType.Equals (OracleType.Cursor)) {
348 if (!foundCursor && parm.Direction != ParameterDirection.Input) {
349 // if there are multiple REF CURSORs,
350 // you only can get the first cursor for now
351 // because user of OracleDataReader
352 // will do a NextResult to get the next
353 // REF CURSOR (if it exists)
356 if (p + 1 == Parameters.Count)
367 internal void CloseDataReader ()
369 Connection.DataReader = null;
370 if ((behavior & CommandBehavior.CloseConnection) != 0)
378 OracleParameter CreateParameter ()
380 return new OracleParameter ();
383 internal void DeriveParameters ()
385 if (commandType != CommandType.StoredProcedure)
386 throw new InvalidOperationException (String.Format ("OracleCommandBuilder DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
388 //OracleParameterCollection localParameters = new OracleParameterCollection (this);
390 throw new NotImplementedException ();
393 private int ExecuteNonQueryInternal (OciStatementHandle statement, bool useAutoCommit)
397 if (preparedStatement == null)
398 PrepareStatement (statement);
400 bool isNonQuery = IsNonQuery (statement);
402 BindParameters (statement);
403 if (isNonQuery == true)
404 statement.ExecuteNonQuery (useAutoCommit);
406 statement.ExecuteQuery (false);
408 UpdateParameterValues ();
410 int rowsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, ErrorHandle);
419 int ExecuteNonQuery ()
423 AssertConnectionIsOpen ();
424 AssertTransactionMatch ();
425 AssertCommandTextIsSet ();
426 bool useAutoCommit = false;
428 if (Transaction != null)
429 Transaction.AttachToServiceContext ();
431 useAutoCommit = true;
433 OciStatementHandle statement = GetStatementHandle ();
435 return ExecuteNonQueryInternal (statement, useAutoCommit);
437 SafeDisposeHandle (statement);
441 public int ExecuteOracleNonQuery (out OracleString rowid)
445 AssertConnectionIsOpen ();
446 AssertTransactionMatch ();
447 AssertCommandTextIsSet ();
448 bool useAutoCommit = false;
450 if (Transaction != null)
451 Transaction.AttachToServiceContext ();
453 useAutoCommit = true;
455 OciStatementHandle statement = GetStatementHandle ();
458 int retval = ExecuteNonQueryInternal (statement, useAutoCommit);
459 OciRowIdDescriptor rowIdDescriptor = statement.GetAttributeRowIdDescriptor (ErrorHandle, Environment);
460 string srowid = rowIdDescriptor.GetRowIdToString (ErrorHandle);
461 rowid = new OracleString (srowid);
462 rowIdDescriptor = null;
465 SafeDisposeHandle (statement);
469 public object ExecuteOracleScalar ()
473 object output = DBNull.Value;
475 AssertConnectionIsOpen ();
476 AssertTransactionMatch ();
477 AssertCommandTextIsSet ();
479 if (Transaction != null)
480 Transaction.AttachToServiceContext ();
482 OciStatementHandle statement = GetStatementHandle ();
484 if (preparedStatement == null)
485 PrepareStatement (statement);
487 bool isNonQuery = IsNonQuery (statement);
489 BindParameters (statement);
491 if (isNonQuery == true)
492 ExecuteNonQueryInternal (statement, false);
494 statement.ExecuteQuery (false);
496 if (statement.Fetch ()) {
497 OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
498 if (!defineHandle.IsNull)
499 output = defineHandle.GetOracleValue (Connection.SessionFormatProvider, Connection);
500 switch (defineHandle.DataType) {
501 case OciDataType.Blob:
502 case OciDataType.Clob:
503 ((OracleLob) output).connection = Connection;
507 UpdateParameterValues ();
512 SafeDisposeHandle (statement);
516 private bool IsNonQuery (OciStatementHandle statementHandle)
518 // assumes Prepare() has been called prior to calling this function
520 OciStatementType statementType = statementHandle.GetStatementType ();
521 if (statementType.Equals (OciStatementType.Select))
531 OracleDataReader ExecuteReader ()
533 return ExecuteReader (CommandBehavior.Default);
540 OracleDataReader ExecuteReader (CommandBehavior behavior)
542 AssertConnectionIsOpen ();
543 AssertTransactionMatch ();
544 AssertCommandTextIsSet ();
548 bool hasRows = false;
550 this.behavior = behavior;
552 if (Transaction != null)
553 Transaction.AttachToServiceContext ();
555 OciStatementHandle statement = GetStatementHandle ();
556 OracleDataReader rd = null;
559 if (preparedStatement == null)
560 PrepareStatement (statement);
562 preparedStatement = null; // OracleDataReader releases the statement handle
564 bool isNonQuery = IsNonQuery (statement);
566 BindParameters (statement);
569 ExecuteNonQueryInternal (statement, false);
571 if ((behavior & CommandBehavior.SchemaOnly) != 0)
572 statement.ExecuteQuery (true);
574 hasRows = statement.ExecuteQuery (false);
576 UpdateParameterValues ();
579 if (Parameters.Count > 0) {
580 for (int p = 0; p < Parameters.Count; p++) {
581 OracleParameter parm = Parameters [p];
582 if (parm.OracleType.Equals (OracleType.Cursor)) {
583 if (parm.Direction != ParameterDirection.Input) {
584 rd = (OracleDataReader) parm.Value;
592 rd = new OracleDataReader (this, statement, hasRows, behavior);
595 if (statement != null && rd == null)
606 object ExecuteScalar ()
609 object output = null;//if we find nothing we return this
611 AssertConnectionIsOpen ();
612 AssertTransactionMatch ();
613 AssertCommandTextIsSet ();
615 if (Transaction != null)
616 Transaction.AttachToServiceContext ();
618 OciStatementHandle statement = GetStatementHandle ();
620 if (preparedStatement == null)
621 PrepareStatement (statement);
623 bool isNonQuery = IsNonQuery (statement);
625 BindParameters (statement);
627 if (isNonQuery == true)
628 ExecuteNonQueryInternal (statement, false);
630 statement.ExecuteQuery (false);
632 if (statement.Fetch ()) {
633 OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
634 if (!defineHandle.IsNull)
636 switch (defineHandle.DataType) {
637 case OciDataType.Blob:
638 case OciDataType.Clob:
639 OracleLob lob = (OracleLob) defineHandle.GetValue (
640 Connection.SessionFormatProvider, Connection);
641 lob.connection = Connection;
646 output = defineHandle.GetValue (
647 Connection.SessionFormatProvider, Connection);
652 UpdateParameterValues ();
655 SafeDisposeHandle (statement);
661 internal OciStatementHandle GetNextResult ()
663 if (moreResults == -1)
666 if (Parameters.Count > 0) {
667 int p = moreResults + 1;
669 if (p >= Parameters.Count) {
674 for (; p < Parameters.Count; p++) {
675 OracleParameter parm = Parameters [p];
676 if (parm.OracleType.Equals (OracleType.Cursor)) {
677 if (parm.Direction != ParameterDirection.Input) {
678 if (p + 1 == Parameters.Count)
682 return parm.GetOutRefCursor (this);
693 private OciStatementHandle GetStatementHandle ()
695 AssertConnectionIsOpen ();
696 if (preparedStatement != null)
697 return preparedStatement;
699 OciStatementHandle h = (OciStatementHandle) Connection.Environment.Allocate (OciHandleType.Statement);
700 h.ErrorHandle = Connection.ErrorHandle;
701 h.Service = Connection.ServiceContext;
706 private void SafeDisposeHandle (OciStatementHandle h)
708 if (h != null && h != preparedStatement)
713 IDbDataParameter IDbCommand.CreateParameter ()
715 return CreateParameter ();
718 IDataReader IDbCommand.ExecuteReader ()
720 return ExecuteReader ();
723 IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
725 return ExecuteReader (behavior);
729 void PrepareStatement (OciStatementHandle statement)
731 if (commandType == CommandType.StoredProcedure) {
732 StringBuilder sb = new StringBuilder ();
733 if (Parameters.Count > 0)
734 foreach (OracleParameter parm in Parameters) {
737 sb.Append (parm.ParameterName + "=>:" + parm.ParameterName);
740 string sql = "begin " + commandText + "(" + sb.ToString() + "); end;";
741 statement.Prepare (sql);
743 statement.Prepare (commandText);
752 AssertConnectionIsOpen ();
753 OciStatementHandle statement = GetStatementHandle ();
754 PrepareStatement (statement);
755 preparedStatement = statement;
758 protected override void Dispose (bool disposing)
761 if (Parameters.Count > 0)
762 foreach (OracleParameter parm in Parameters)
764 base.Dispose (disposing);
767 #endregion // Methods