* OciGlue.cs: Set eol-style to native.
[mono.git] / mcs / class / System.Data.OracleClient / System.Data.OracleClient / OracleCommand.cs
old mode 100755 (executable)
new mode 100644 (file)
index 63efa3f..1bbc3bc
@@ -8,10 +8,10 @@
 // Namespace: System.Data.OracleClient
 //
 // Authors: 
-//    Daniel Morgan <danmorg@sc.rr.com>
+//    Daniel Morgan <danielmorgan@verizon.net>
 //    Tim Coleman <tim@timcoleman.com>
 //
-// Copyright (C) Daniel Morgan, 2002
+// Copyright (C) Daniel Morgan, 2002, 2004-2005
 // Copyright (C) Tim Coleman , 2003
 //
 // Licensed under the MIT/X11 License.
@@ -21,13 +21,16 @@ using System;
 using System.ComponentModel;
 using System.Data;
 using System.Data.OracleClient.Oci;
+using System.Drawing.Design;
+using System.Text;
 
 namespace System.Data.OracleClient {
-       public class OracleCommand : Component, ICloneable, IDbCommand
+       [Designer ("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + Consts.AssemblyMicrosoft_VSDesigner)]
+       [ToolboxItem (true)]
+       public sealed class OracleCommand : Component, ICloneable, IDbCommand
        {
                #region Fields
 
-               bool disposed = false;
                CommandBehavior behavior;
                string commandText;
                CommandType commandType;
@@ -37,7 +40,7 @@ namespace System.Data.OracleClient {
                OracleTransaction transaction;
                UpdateRowSource updatedRowSource;
 
-               OciStatementHandle preparedStatement;
+               private OciStatementHandle preparedStatement;
                OciStatementType statementType;
 
                #endregion // Fields
@@ -69,28 +72,42 @@ namespace System.Data.OracleClient {
                        UpdatedRowSource = UpdateRowSource.Both;
                        DesignTimeVisible = false;
 
-                        parameters = new OracleParameterCollection (this);
+                       parameters = new OracleParameterCollection (this);
                }
 
                #endregion // Constructors
 
                #region Properties
 
+               [DefaultValue ("")]
+               [RefreshProperties (RefreshProperties.All)]
+               [Editor ("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
                public string CommandText {
                        get { return commandText; }
                        set { commandText = value; }
                }
 
+               [RefreshProperties (RefreshProperties.All)]
+               [DefaultValue (CommandType.Text)]
                public CommandType CommandType {
                        get { return commandType; }
-                       set { commandType = value; }
+                       set { 
+                               if (value == CommandType.TableDirect)
+                                       throw new ArgumentException ("OracleClient provider does not support TableDirect CommandType.");
+                               commandType = value; 
+                       }
                }
 
+               [DefaultValue (null)]
+               [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
                public OracleConnection Connection {
                        get { return connection; }
                        set { connection = value; }
                }
 
+               [DefaultValue (true)]
+               [Browsable (false)]
+               [DesignOnly (true)]
                public bool DesignTimeVisible {
                        get { return designTimeVisible; }
                        set { designTimeVisible = value; }
@@ -109,6 +126,8 @@ namespace System.Data.OracleClient {
                        set { }
                }
 
+               [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
+               [DefaultValue (null)]
                IDbConnection IDbCommand.Connection {
                        get { return Connection; }
                        set { 
@@ -131,15 +150,19 @@ namespace System.Data.OracleClient {
                        }
                }
 
+               [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
                public OracleParameterCollection Parameters {
                        get { return parameters; }
                }
 
+               [Browsable (false)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public OracleTransaction Transaction {
                        get { return transaction; }
                        set { transaction = value; }
                }
 
+               [DefaultValue (UpdateRowSource.Both)]
                public UpdateRowSource UpdatedRowSource {
                        get { return updatedRowSource; }
                        set { updatedRowSource = value; }
@@ -175,8 +198,8 @@ namespace System.Data.OracleClient {
 
                private void BindParameters (OciStatementHandle statement)
                {
-                       foreach (OracleParameter p in Parameters) 
-                               p.Bind (statement, Connection);
+                       for (int p = 0; p < Parameters.Count; p++)
+                               Parameters[p].Bind (statement, Connection, (uint) p);
                }
 
                [MonoTODO]
@@ -188,11 +211,58 @@ namespace System.Data.OracleClient {
                [MonoTODO]
                public object Clone ()
                {
-                       throw new NotImplementedException ();
+                       // create a new OracleCommand object with the same properties
+                       
+                       OracleCommand cmd = new OracleCommand ();
+                       
+                       cmd.CommandText = this.CommandText;
+                       cmd.CommandType = this.CommandType;
+
+                       // FIXME: not sure if I should set the same object here
+                       // or get a clone of these too
+                       cmd.Connection = this.Connection;
+                       cmd.Transaction = this.Transaction;
+                       
+                       foreach (OracleParameter parm in this.Parameters) {
+
+                               OracleParameter newParm = cmd.CreateParameter ();
+
+                               newParm.DbType = parm.DbType;
+                               newParm.Direction = parm.Direction;
+                               newParm.IsNullable = parm.IsNullable;
+                               newParm.Offset = parm.Offset;
+                               newParm.OracleType = parm.OracleType;
+                               newParm.ParameterName = parm.ParameterName;
+                               newParm.Precision = parm.Precision;
+                               newParm.Scale = parm.Scale;
+                               newParm.SourceColumn = parm.SourceColumn;
+                               newParm.SourceVersion = parm.SourceVersion;
+                               newParm.Value = parm.Value;
+
+                               cmd.Parameters.Add (newParm);
+                       }
+
+                       //cmd.Container = this.Container;
+                       cmd.DesignTimeVisible = this.DesignTimeVisible;
+                       //cmd.DesignMode = this.DesignMode;
+                       cmd.Site = this.Site;
+                       //cmd.UpdateRowSource = this.UpdateRowSource;
+
+                       return cmd;
+               }
+
+               internal void UpdateParameterValues () 
+               {
+                       if (Parameters.Count > 0) {
+                               foreach (OracleParameter parm in Parameters)
+                                       parm.Update (this);
+                       }
                }
 
                internal void CloseDataReader ()
                {
+                       UpdateParameterValues ();
+               
                        Connection.DataReader = null;
                        if ((behavior & CommandBehavior.CloseConnection) != 0)
                                Connection.Close ();
@@ -203,17 +273,33 @@ namespace System.Data.OracleClient {
                        return new OracleParameter ();
                }
 
-               private int ExecuteNonQueryInternal (OciStatementHandle statement)
+               internal void DeriveParameters () 
+               {
+                       if (commandType != CommandType.StoredProcedure)
+                               throw new InvalidOperationException (String.Format ("OracleCommandBuilder DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
+
+                       //OracleParameterCollection localParameters = new OracleParameterCollection (this);
+
+                       throw new NotImplementedException ();
+               }
+
+               private int ExecuteNonQueryInternal (OciStatementHandle statement, bool useAutoCommit)
                {
                        if (preparedStatement == null)
-                               statement.Prepare (CommandText);
+                               PrepareStatement (statement);
+
+                       bool isNonQuery = IsNonQuery (statement);
 
                        BindParameters (statement);
-                       statement.ExecuteNonQuery ();
+                       if (isNonQuery == true)
+                               statement.ExecuteNonQuery (useAutoCommit);
+                       else
+                               statement.ExecuteQuery (false);
+
+                       UpdateParameterValues ();
 
                        int rowsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, ErrorHandle);
-                       
-                       statement.Dispose ();
+               
                        return rowsAffected;
                }
 
@@ -222,11 +308,20 @@ namespace System.Data.OracleClient {
                        AssertConnectionIsOpen ();
                        AssertTransactionMatch ();
                        AssertCommandTextIsSet ();
+                       bool useAutoCommit = false; 
 
                        if (Transaction != null)
                                Transaction.AttachToServiceContext ();
+                       else
+                               useAutoCommit = true;
 
-                       return ExecuteNonQueryInternal (GetStatementHandle ());
+                       OciStatementHandle statement = GetStatementHandle ();
+                       try {
+                               return ExecuteNonQueryInternal (statement, useAutoCommit);
+                       }
+                       finally {
+                               SafeDisposeHandle (statement);
+                       }
                }
 
                public int ExecuteOracleNonQuery (out OracleString rowid)
@@ -234,26 +329,86 @@ namespace System.Data.OracleClient {
                        AssertConnectionIsOpen ();
                        AssertTransactionMatch ();
                        AssertCommandTextIsSet ();
+                       bool useAutoCommit = false; 
 
                        if (Transaction != null)
                                Transaction.AttachToServiceContext ();
+                       else
+                               useAutoCommit = true;
 
                        OciStatementHandle statement = GetStatementHandle ();
 
-                       int retval = ExecuteNonQueryInternal (statement);
+                       try {
+                               int retval = ExecuteNonQueryInternal (statement, useAutoCommit);
 
-                       OciRowIdDescriptor descriptor = (OciRowIdDescriptor) Environment.Allocate (OciHandleType.RowId);
-                       descriptor.SetHandle (statement.GetAttributeIntPtr (OciAttributeType.RowId, ErrorHandle));
+                               OciRowIdDescriptor descriptor = (OciRowIdDescriptor) Environment.Allocate (OciHandleType.RowId);
+                               descriptor.SetHandle (statement.GetAttributeIntPtr (OciAttributeType.RowId, ErrorHandle));
 
-                       rowid = new OracleString (descriptor.GetRowId (ErrorHandle));
+                               rowid = new OracleString (descriptor.GetRowId (ErrorHandle));
 
-                       return retval;
+                               return retval;
+                       }
+                       finally {
+                               SafeDisposeHandle (statement);
+                       }
                }
 
                [MonoTODO]
-               public object ExecuteOracleScalar (out OracleString rowid)
+               public object ExecuteOracleScalar ()
                {
-                       throw new NotImplementedException ();
+                       object output = DBNull.Value;
+
+                       AssertConnectionIsOpen ();
+                       AssertTransactionMatch ();
+                       AssertCommandTextIsSet ();
+
+                       if (Transaction != null)
+                               Transaction.AttachToServiceContext ();
+
+                       OciStatementHandle statement = GetStatementHandle ();
+                       try {
+                               if (preparedStatement == null)
+                                       PrepareStatement (statement);
+
+                               bool isNonQuery = IsNonQuery (statement);
+
+                               BindParameters (statement);
+
+                               if (isNonQuery == true)
+                                       ExecuteNonQueryInternal (statement, false);
+                               else {
+                                       statement.ExecuteQuery (false);
+
+                                       if (statement.Fetch ()) {
+                                               OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
+                                               if (!defineHandle.IsNull)
+                                                       output = defineHandle.GetOracleValue ();
+                                               switch (defineHandle.DataType) {
+                                               case OciDataType.Blob:
+                                               case OciDataType.Clob:
+                                                       ((OracleLob) output).connection = Connection;
+                                                       break;
+                                               }
+                                       }
+                                       UpdateParameterValues ();
+                               }
+
+                               return output;
+                       }
+                       finally {
+                               SafeDisposeHandle (statement);
+                       }
+               }
+
+               private bool IsNonQuery (OciStatementHandle statementHandle) 
+               {
+                       // assumes Prepare() has been called prior to calling this function
+
+                       OciStatementType statementType = statementHandle.GetStatementType ();
+                       if (statementType.Equals (OciStatementType.Select))
+                               return false;
+
+                       return true;
                }
 
                public OracleDataReader ExecuteReader ()
@@ -267,23 +422,48 @@ namespace System.Data.OracleClient {
                        AssertTransactionMatch ();
                        AssertCommandTextIsSet ();
                        AssertNoDataReader ();
+                       bool hasRows = false;
 
-                       if (Transaction != null)
+                        this.behavior = behavior;
+                               
+                       if (Transaction != null) 
                                Transaction.AttachToServiceContext ();
-
+                       
                        OciStatementHandle statement = GetStatementHandle ();
+                       OracleDataReader rd = null;
 
-                       if (preparedStatement == null)
-                               statement.Prepare (CommandText);
-                       BindParameters (statement);
-                       statement.ExecuteQuery ();
+                       try     {
+                               if (preparedStatement == null)
+                                       PrepareStatement (statement);
+                               else
+                                       preparedStatement = null;       // OracleDataReader releases the statement handle
+
+                               bool isNonQuery = IsNonQuery (statement);
+
+                               BindParameters (statement);
 
-                       return new OracleDataReader (this, statement);
+                               if (isNonQuery)
+                                       ExecuteNonQueryInternal (statement, false);
+                               else {
+                                       if ((behavior & CommandBehavior.SchemaOnly) != 0)
+                                               statement.ExecuteQuery (true);
+                                       else
+                                               hasRows = statement.ExecuteQuery (false);
+                               }
+
+                               rd = new OracleDataReader (this, statement, hasRows, behavior);
+                       }
+                       finally {
+                               if (statement != null && rd == null)
+                                       statement.Dispose();
+                       }
+
+                       return rd;
                }
 
                public object ExecuteScalar ()
                {
-                       object output;
+                       object output = DBNull.Value;
 
                        AssertConnectionIsOpen ();
                        AssertTransactionMatch ();
@@ -293,16 +473,46 @@ namespace System.Data.OracleClient {
                                Transaction.AttachToServiceContext ();
 
                        OciStatementHandle statement = GetStatementHandle ();
-                       if (preparedStatement == null)
-                               statement.Prepare (CommandText);
-                       BindParameters (statement);
-
-                       statement.ExecuteQuery ();
-
-                       if (statement.Fetch ()) 
-                               output = ((OciDefineHandle) statement.Values [0]).GetValue ();
-                       else
-                               output = DBNull.Value;
+                       try {
+                               if (preparedStatement == null)
+                                       PrepareStatement (statement);
+
+                               bool isNonQuery = IsNonQuery (statement);
+
+                               BindParameters (statement);
+
+                               if (isNonQuery == true)
+                                       ExecuteNonQueryInternal (statement, false);
+                               else {
+                                       statement.ExecuteQuery (false);
+
+                                       if (statement.Fetch ()) {
+                                               OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
+                                               if (defineHandle.IsNull)
+                                                       output = DBNull.Value;
+                                               else {
+                                                       switch (defineHandle.DataType) {
+                                                       case OciDataType.Blob:
+                                                       case OciDataType.Clob:
+                                                               OracleLob lob = (OracleLob) defineHandle.GetValue ();
+                                                               lob.connection = Connection;
+                                                               output = lob.Value;
+                                                               lob.Close ();
+                                                               break;
+                                                       default:
+                                                               output = defineHandle.GetValue ();
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       else
+                                               output = DBNull.Value;
+                                       UpdateParameterValues ();
+                               }
+                       }
+                       finally {
+                               SafeDisposeHandle (statement);
+                       }
 
                        return output;
                }
@@ -316,9 +526,16 @@ namespace System.Data.OracleClient {
                        OciStatementHandle h = (OciStatementHandle) Connection.Environment.Allocate (OciHandleType.Statement);
                        h.ErrorHandle = Connection.ErrorHandle;
                        h.Service = Connection.ServiceContext;
+                       h.Command = this;
                        return h;
                }
 
+               private void SafeDisposeHandle (OciStatementHandle h)
+               {
+                       if (h != null && h != preparedStatement) 
+                               h.Dispose();
+               }
+
                IDbDataParameter IDbCommand.CreateParameter ()
                {
                        return CreateParameter ();
@@ -334,11 +551,29 @@ namespace System.Data.OracleClient {
                        return ExecuteReader (behavior);
                }
 
+               void PrepareStatement (OciStatementHandle statement) 
+               {
+                       if (commandType == CommandType.StoredProcedure) {
+                               StringBuilder sb = new StringBuilder ();
+                               if (Parameters.Count > 0)
+                                       foreach (OracleParameter parm in Parameters) {
+                                               if (sb.Length > 0)
+                                                       sb.Append (",");
+                                               sb.Append (":" + parm.ParameterName);
+                                       }
+
+                               string sql = "call " + commandText + "(" + sb.ToString() + ")";
+                               statement.Prepare (sql);
+                       }
+                       else    // Text
+                               statement.Prepare (commandText);
+               }
+
                public void Prepare ()
                {
                        AssertConnectionIsOpen ();
                        OciStatementHandle statement = GetStatementHandle ();
-                       statement.Prepare (CommandText);
+                       PrepareStatement (statement);
                        preparedStatement = statement;
                }