2009-11-21 Daniel Morgan <monodanmorg@yahoo.com>
[mono.git] / mcs / class / System.Data.OracleClient / System.Data.OracleClient / OracleCommand.cs
old mode 100755 (executable)
new mode 100644 (file)
index d461786..db39d3d
@@ -1,4 +1,4 @@
-// 
+//
 // OracleCommand.cs
 //
 // Part of the Mono class libraries at
@@ -7,9 +7,10 @@
 // Assembly: System.Data.OracleClient.dll
 // Namespace: System.Data.OracleClient
 //
-// Authors: 
+// Authors:
 //    Daniel Morgan <danielmorgan@verizon.net>
 //    Tim Coleman <tim@timcoleman.com>
+//    Marek Safar <marek.safar@gmail.com>
 //
 // Copyright (C) Daniel Morgan, 2002, 2004-2005
 // Copyright (C) Tim Coleman , 2003
 using System;
 using System.ComponentModel;
 using System.Data;
+#if NET_2_0
+using System.Data.Common;
+#endif
 using System.Data.OracleClient.Oci;
 using System.Drawing.Design;
 using System.Text;
 
-namespace System.Data.OracleClient {
+namespace System.Data.OracleClient
+{
+#if NET_2_0
+       [DefaultEvent ("RecordsAffected")]
+#endif
        [Designer ("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + Consts.AssemblyMicrosoft_VSDesigner)]
        [ToolboxItem (true)]
-       public sealed class OracleCommand : Component, ICloneable, IDbCommand
+       public sealed class OracleCommand :
+#if NET_2_0
+               DbCommand, ICloneable
+#else
+               Component, ICloneable, IDbCommand
+#endif
        {
                #region Fields
 
@@ -39,9 +52,9 @@ namespace System.Data.OracleClient {
                OracleParameterCollection parameters;
                OracleTransaction transaction;
                UpdateRowSource updatedRowSource;
-
-               private OciStatementHandle preparedStatement;
-               OciStatementType statementType;
+               OciStatementHandle preparedStatement;
+               
+               int moreResults;
 
                #endregion // Fields
 
@@ -64,15 +77,15 @@ namespace System.Data.OracleClient {
 
                public OracleCommand (string commandText, OracleConnection connection, OracleTransaction tx)
                {
+                       moreResults = -1;
                        preparedStatement = null;
                        CommandText = commandText;
                        Connection = connection;
                        Transaction = tx;
                        CommandType = CommandType.Text;
                        UpdatedRowSource = UpdateRowSource.Both;
-                       DesignTimeVisible = false;
-
-                       parameters = new OracleParameterCollection (this);
+                       DesignTimeVisible = true;
+                       parameters = new OracleParameterCollection ();
                }
 
                #endregion // Constructors
@@ -82,33 +95,84 @@ namespace System.Data.OracleClient {
                [DefaultValue ("")]
                [RefreshProperties (RefreshProperties.All)]
                [Editor ("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
-               public string CommandText {
-                       get { return commandText; }
+               public
+#if NET_2_0
+               override
+#endif
+               string CommandText {
+                       get {
+                               if (commandText == null)
+                                       return string.Empty;
+
+                               return commandText;
+                       }
                        set { commandText = value; }
                }
 
                [RefreshProperties (RefreshProperties.All)]
                [DefaultValue (CommandType.Text)]
-               public CommandType CommandType {
+               public
+#if NET_2_0
+               override
+#endif
+               CommandType CommandType {
                        get { return commandType; }
-                       set { 
+                       set {
                                if (value == CommandType.TableDirect)
                                        throw new ArgumentException ("OracleClient provider does not support TableDirect CommandType.");
-                               commandType = value; 
+                               commandType = value;
                        }
                }
 
                [DefaultValue (null)]
                [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
-               public OracleConnection Connection {
+               public
+#if NET_2_0
+               new
+#endif
+               OracleConnection Connection {
                        get { return connection; }
                        set { connection = value; }
                }
 
+#if NET_2_0
+               [Browsable (false)]
+               [EditorBrowsable (EditorBrowsableState.Never)]
+               [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+               public override int CommandTimeout {
+                       get { return 0; }
+                       set { }
+               }
+
+               [MonoTODO]
+               protected override DbConnection DbConnection {
+                       get { return Connection; }
+                       set { Connection = (OracleConnection) value; }
+               }
+
+               [MonoTODO]
+               protected override DbParameterCollection DbParameterCollection {
+                       get { return Parameters; }
+               }
+
+               [MonoTODO]
+               protected override DbTransaction DbTransaction {
+                       get { return Transaction; }
+                       set { Transaction = (OracleTransaction) value; }
+               }
+#endif
+
                [DefaultValue (true)]
                [Browsable (false)]
                [DesignOnly (true)]
-               public bool DesignTimeVisible {
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Never)]
+#endif
+               public
+#if NET_2_0
+               override
+#endif
+               bool DesignTimeVisible {
                        get { return designTimeVisible; }
                        set { designTimeVisible = value; }
                }
@@ -121,6 +185,7 @@ namespace System.Data.OracleClient {
                        get { return Connection.ErrorHandle; }
                }
 
+#if !NET_2_0
                int IDbCommand.CommandTimeout {
                        get { return 0; }
                        set { }
@@ -130,9 +195,8 @@ namespace System.Data.OracleClient {
                [DefaultValue (null)]
                IDbConnection IDbCommand.Connection {
                        get { return Connection; }
-                       set { 
-                               if (!(value is OracleConnection))
-                                       throw new InvalidCastException ("The value was not a valid OracleConnection.");
+                       set {
+                               // InvalidCastException is expected when types do not match
                                Connection = (OracleConnection) value;
                        }
                }
@@ -143,27 +207,39 @@ namespace System.Data.OracleClient {
 
                IDbTransaction IDbCommand.Transaction {
                        get { return Transaction; }
-                       set { 
-                               if (!(value is OracleTransaction))
-                                       throw new ArgumentException ();
-                               Transaction = (OracleTransaction) value; 
+                       set {
+                               // InvalidCastException is expected when types do not match
+                               Transaction = (OracleTransaction) value;
                        }
                }
+#endif
 
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
-               public OracleParameterCollection Parameters {
+               public
+#if NET_2_0
+               new
+#endif
+               OracleParameterCollection Parameters {
                        get { return parameters; }
                }
 
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public OracleTransaction Transaction {
+               public
+#if NET_2_0
+               new
+#endif
+               OracleTransaction Transaction {
                        get { return transaction; }
                        set { transaction = value; }
                }
 
                [DefaultValue (UpdateRowSource.Both)]
-               public UpdateRowSource UpdatedRowSource {
+               public
+#if NET_2_0
+               override
+#endif
+               UpdateRowSource UpdatedRowSource {
                        get { return updatedRowSource; }
                        set { updatedRowSource = value; }
                }
@@ -174,7 +250,7 @@ namespace System.Data.OracleClient {
 
                private void AssertCommandTextIsSet ()
                {
-                       if (CommandText == String.Empty || CommandText == null)
+                       if (CommandText.Length == 0)
                                throw new InvalidOperationException ("The command text for this Command has not been set.");
                }
 
@@ -184,12 +260,6 @@ namespace System.Data.OracleClient {
                                throw new InvalidOperationException ("An open Connection object is required to continue.");
                }
 
-               private void AssertNoDataReader ()
-               {
-                       if (Connection.DataReader != null)
-                               throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
-               }
-
                private void AssertTransactionMatch ()
                {
                        if (Connection.Transaction != null && Transaction != Connection.Transaction)
@@ -198,12 +268,16 @@ 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]
-               public void Cancel ()
+               public
+#if NET_2_0
+               override
+#endif
+               void Cancel ()
                {
                        throw new NotImplementedException ();
                }
@@ -212,9 +286,9 @@ namespace System.Data.OracleClient {
                public object Clone ()
                {
                        // create a new OracleCommand object with the same properties
-                       
+
                        OracleCommand cmd = new OracleCommand ();
-                       
+
                        cmd.CommandText = this.CommandText;
                        cmd.CommandType = this.CommandType;
 
@@ -222,7 +296,7 @@ namespace System.Data.OracleClient {
                        // 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 ();
@@ -233,8 +307,8 @@ namespace System.Data.OracleClient {
                                newParm.Offset = parm.Offset;
                                newParm.OracleType = parm.OracleType;
                                newParm.ParameterName = parm.ParameterName;
-                               newParm.Precision = parm.Precision;
-                               newParm.Scale = parm.Scale;
+                               //newParm.Precision = parm.Precision;
+                               //newParm.Scale = parm.Scale;
                                newParm.SourceColumn = parm.SourceColumn;
                                newParm.SourceVersion = parm.SourceVersion;
                                newParm.Value = parm.Value;
@@ -251,6 +325,45 @@ namespace System.Data.OracleClient {
                        return cmd;
                }
 
+#if NET_2_0
+               protected override DbParameter CreateDbParameter ()
+               {
+                       return CreateParameter ();
+               }
+
+               protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
+               {
+                       return ExecuteReader (behavior);
+               }
+#endif
+
+               internal void UpdateParameterValues ()
+               {
+                       moreResults = -1;
+                       if (Parameters.Count > 0) {
+                               bool foundCursor = false;
+                               for (int p = 0; p < Parameters.Count; p++) {
+                                       OracleParameter parm = Parameters [p];
+                                       if (parm.OracleType.Equals (OracleType.Cursor)) {
+                                               if (!foundCursor && parm.Direction != ParameterDirection.Input) {
+                                                       // if there are multiple REF CURSORs,
+                                                       // you only can get the first cursor for now
+                                                       // because user of OracleDataReader
+                                                       // will do a NextResult to get the next 
+                                                       // REF CURSOR (if it exists)
+                                                       foundCursor = true;
+                                                       parm.Update (this);
+                                                       if (p + 1 == Parameters.Count)
+                                                               moreResults = -1;
+                                                       else
+                                                               moreResults = p;
+                                               }
+                                       } else
+                                               parm.Update (this);
+                               }
+                       }
+               }
+
                internal void CloseDataReader ()
                {
                        Connection.DataReader = null;
@@ -258,13 +371,29 @@ namespace System.Data.OracleClient {
                                Connection.Close ();
                }
 
-               public OracleParameter CreateParameter ()
+               public
+#if NET_2_0
+               new
+#endif
+               OracleParameter CreateParameter ()
                {
                        return new OracleParameter ();
                }
 
+               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)
                {
+                       moreResults = -1;
+
                        if (preparedStatement == null)
                                PrepareStatement (statement);
 
@@ -274,19 +403,27 @@ namespace System.Data.OracleClient {
                        if (isNonQuery == true)
                                statement.ExecuteNonQuery (useAutoCommit);
                        else
-                               statement.ExecuteQuery ();
+                               statement.ExecuteQuery (false);
+
+                       UpdateParameterValues ();
 
                        int rowsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, ErrorHandle);
-               
+
                        return rowsAffected;
                }
 
-               public int ExecuteNonQuery () 
+               public
+#if NET_2_0
+               override
+#endif
+               int ExecuteNonQuery ()
                {
+                       moreResults = -1;
+
                        AssertConnectionIsOpen ();
                        AssertTransactionMatch ();
                        AssertCommandTextIsSet ();
-                       bool useAutoCommit = false; 
+                       bool useAutoCommit = false;
 
                        if (Transaction != null)
                                Transaction.AttachToServiceContext ();
@@ -296,18 +433,19 @@ namespace System.Data.OracleClient {
                        OciStatementHandle statement = GetStatementHandle ();
                        try {
                                return ExecuteNonQueryInternal (statement, useAutoCommit);
-                       }
-                       finally {
+                       } finally {
                                SafeDisposeHandle (statement);
                        }
                }
 
                public int ExecuteOracleNonQuery (out OracleString rowid)
                {
+                       moreResults = -1;
+
                        AssertConnectionIsOpen ();
                        AssertTransactionMatch ();
                        AssertCommandTextIsSet ();
-                       bool useAutoCommit = false; 
+                       bool useAutoCommit = false;
 
                        if (Transaction != null)
                                Transaction.AttachToServiceContext ();
@@ -318,22 +456,20 @@ namespace System.Data.OracleClient {
 
                        try {
                                int retval = ExecuteNonQueryInternal (statement, useAutoCommit);
-
-                               OciRowIdDescriptor descriptor = (OciRowIdDescriptor) Environment.Allocate (OciHandleType.RowId);
-                               descriptor.SetHandle (statement.GetAttributeIntPtr (OciAttributeType.RowId, ErrorHandle));
-
-                               rowid = new OracleString (descriptor.GetRowId (ErrorHandle));
-
+                               OciRowIdDescriptor rowIdDescriptor = statement.GetAttributeRowIdDescriptor (ErrorHandle, Environment);
+                               string srowid = rowIdDescriptor.GetRowIdToString (ErrorHandle);
+                               rowid = new OracleString (srowid);
+                               rowIdDescriptor = null;
                                return retval;
-                       }
-                       finally {
+                       } finally {
                                SafeDisposeHandle (statement);
                        }
                }
 
-               [MonoTODO]
                public object ExecuteOracleScalar ()
                {
+                       moreResults = -1;
+
                        object output = DBNull.Value;
 
                        AssertConnectionIsOpen ();
@@ -355,12 +491,12 @@ namespace System.Data.OracleClient {
                                if (isNonQuery == true)
                                        ExecuteNonQueryInternal (statement, false);
                                else {
-                                       statement.ExecuteQuery ();
+                                       statement.ExecuteQuery (false);
 
                                        if (statement.Fetch ()) {
                                                OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
                                                if (!defineHandle.IsNull)
-                                                       output = defineHandle.GetOracleValue ();
+                                                       output = defineHandle.GetOracleValue (Connection.SessionFormatProvider, Connection);
                                                switch (defineHandle.DataType) {
                                                case OciDataType.Blob:
                                                case OciDataType.Clob:
@@ -368,16 +504,16 @@ namespace System.Data.OracleClient {
                                                        break;
                                                }
                                        }
+                                       UpdateParameterValues ();
                                }
 
                                return output;
-                       }
-                       finally {
+                       } finally {
                                SafeDisposeHandle (statement);
                        }
                }
 
-               private bool IsNonQuery (OciStatementHandle statementHandle) \r
+               private bool IsNonQuery (OciStatementHandle statementHandle)
                {
                        // assumes Prepare() has been called prior to calling this function
 
@@ -388,28 +524,38 @@ namespace System.Data.OracleClient {
                        return true;
                }
 
-               public OracleDataReader ExecuteReader ()
+               public
+#if NET_2_0
+               new
+#endif
+               OracleDataReader ExecuteReader ()
                {
                        return ExecuteReader (CommandBehavior.Default);
                }
 
-               public OracleDataReader ExecuteReader (CommandBehavior behavior)
+               public
+#if NET_2_0
+               new
+#endif
+               OracleDataReader ExecuteReader (CommandBehavior behavior)
                {
                        AssertConnectionIsOpen ();
                        AssertTransactionMatch ();
                        AssertCommandTextIsSet ();
-                       AssertNoDataReader ();
+
+                       moreResults = -1;
+
                        bool hasRows = false;
 
-                        this.behavior = behavior;
-                               
-                       if (Transaction != null) 
+                       this.behavior = behavior;
+
+                       if (Transaction != null)
                                Transaction.AttachToServiceContext ();
-                       
+
                        OciStatementHandle statement = GetStatementHandle ();
                        OracleDataReader rd = null;
 
-                       try     {
+                       try {
                                if (preparedStatement == null)
                                        PrepareStatement (statement);
                                else
@@ -419,14 +565,33 @@ namespace System.Data.OracleClient {
 
                                BindParameters (statement);
 
-                               if (isNonQuery)
+                               if (isNonQuery) 
                                        ExecuteNonQueryInternal (statement, false);
-                               else
-                                       hasRows = statement.ExecuteQuery ();
+                               else {  
+                                       if ((behavior & CommandBehavior.SchemaOnly) != 0)
+                                               statement.ExecuteQuery (true);
+                                       else
+                                               hasRows = statement.ExecuteQuery (false);
 
-                               rd = new OracleDataReader (this, statement, hasRows);
-                       }
-                       finally {
+                                       UpdateParameterValues ();
+                               }
+
+                               if (Parameters.Count > 0) {
+                                       for (int p = 0; p < Parameters.Count; p++) {
+                                               OracleParameter parm = Parameters [p];
+                                               if (parm.OracleType.Equals (OracleType.Cursor)) {
+                                                       if (parm.Direction != ParameterDirection.Input) {
+                                                               rd = (OracleDataReader) parm.Value;
+                                                               break;
+                                                       }
+                                               }
+                                       }                                       
+                               }
+
+                               if (rd == null)
+                                       rd = new OracleDataReader (this, statement, hasRows, behavior);
+
+                       } finally {
                                if (statement != null && rd == null)
                                        statement.Dispose();
                        }
@@ -434,9 +599,14 @@ namespace System.Data.OracleClient {
                        return rd;
                }
 
-               public object ExecuteScalar ()
+               public
+#if NET_2_0
+               override
+#endif
+               object ExecuteScalar ()
                {
-                       object output = DBNull.Value;
+                       moreResults = -1;
+                       object output = null;//if we find nothing we return this
 
                        AssertConnectionIsOpen ();
                        AssertTransactionMatch ();
@@ -457,44 +627,75 @@ namespace System.Data.OracleClient {
                                if (isNonQuery == true)
                                        ExecuteNonQueryInternal (statement, false);
                                else {
-                                       statement.ExecuteQuery ();
+                                       statement.ExecuteQuery (false);
 
                                        if (statement.Fetch ()) {
                                                OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
-                                               if (defineHandle.IsNull)
-                                                       output = DBNull.Value;
-                                               else {
+                                               if (!defineHandle.IsNull)
+                                               {
                                                        switch (defineHandle.DataType) {
                                                        case OciDataType.Blob:
                                                        case OciDataType.Clob:
-                                                               OracleLob lob = (OracleLob) defineHandle.GetValue ();
+                                                               OracleLob lob = (OracleLob) defineHandle.GetValue (
+                                                                       Connection.SessionFormatProvider, Connection);
                                                                lob.connection = Connection;
                                                                output = lob.Value;
                                                                lob.Close ();
                                                                break;
                                                        default:
-                                                               output = defineHandle.GetValue ();
+                                                               output = defineHandle.GetValue (
+                                                                       Connection.SessionFormatProvider, Connection);
                                                                break;
                                                        }
                                                }
                                        }
-                                       else
-                                               output = DBNull.Value;
+                                       UpdateParameterValues ();
                                }
-                       }
-                       finally {
+                       } finally {
                                SafeDisposeHandle (statement);
                        }
 
                        return output;
                }
 
+               internal OciStatementHandle GetNextResult () 
+               {
+                       if (moreResults == -1)
+                               return null;
+
+                       if (Parameters.Count > 0) {
+                               int p = moreResults + 1;
+                               
+                               if (p >= Parameters.Count) {
+                                       moreResults = -1;
+                                       return null;
+                               }
+
+                               for (; p < Parameters.Count; p++) {
+                                       OracleParameter parm = Parameters [p];
+                                       if (parm.OracleType.Equals (OracleType.Cursor)) {
+                                               if (parm.Direction != ParameterDirection.Input) {
+                                                       if (p + 1 == Parameters.Count)
+                                                               moreResults = -1;
+                                                       else 
+                                                               moreResults = p;
+                                                       return parm.GetOutRefCursor (this);
+                                                       
+                                               }
+                                       } 
+                               }
+                       }
+
+                       moreResults = -1;
+                       return null;
+               }
+
                private OciStatementHandle GetStatementHandle ()
                {
                        AssertConnectionIsOpen ();
-                       if (preparedStatement != null) 
+                       if (preparedStatement != null)
                                return preparedStatement;
-                       
+
                        OciStatementHandle h = (OciStatementHandle) Connection.Environment.Allocate (OciHandleType.Statement);
                        h.ErrorHandle = Connection.ErrorHandle;
                        h.Service = Connection.ServiceContext;
@@ -504,10 +705,11 @@ namespace System.Data.OracleClient {
 
                private void SafeDisposeHandle (OciStatementHandle h)
                {
-                       if (h != null && h != preparedStatement) 
+                       if (h != null && h != preparedStatement)
                                h.Dispose();
                }
 
+#if !NET_2_0
                IDbDataParameter IDbCommand.CreateParameter ()
                {
                        return CreateParameter ();
@@ -522,26 +724,30 @@ namespace System.Data.OracleClient {
                {
                        return ExecuteReader (behavior);
                }
+#endif
 
-               void PrepareStatement (OciStatementHandle statement) 
+               void PrepareStatement (OciStatementHandle statement)
                {
                        if (commandType == CommandType.StoredProcedure) {
                                StringBuilder sb = new StringBuilder ();
-                               if (Parameters.Count > 0)\r
-                                       foreach (OracleParameter parm in Parameters) {\r
-                                               if (sb.Length > 0)\r
-                                                       sb.Append (",");\r
-                                               sb.Append (":" + parm.ParameterName);\r
-                                       }\r
-\r
-                               string sql = "call " + commandText + "(" + sb.ToString() + ")";\r
+                               if (Parameters.Count > 0)
+                                       foreach (OracleParameter parm in Parameters) {
+                                               if (sb.Length > 0)
+                                                       sb.Append (",");
+                                               sb.Append (parm.ParameterName + "=>:" + parm.ParameterName);
+                                       }
+
+                               string sql = "begin " + commandText + "(" + sb.ToString() + "); end;";
                                statement.Prepare (sql);
-                       }
-                       else    // Text
+                       } else  // Text
                                statement.Prepare (commandText);
                }
 
-               public void Prepare ()
+               public
+#if NET_2_0
+               override
+#endif
+               void Prepare ()
                {
                        AssertConnectionIsOpen ();
                        OciStatementHandle statement = GetStatementHandle ();
@@ -549,6 +755,15 @@ namespace System.Data.OracleClient {
                        preparedStatement = statement;
                }
 
+               protected override void Dispose (bool disposing)
+               {
+                       if (disposing)
+                               if (Parameters.Count > 0)
+                                       foreach (OracleParameter parm in Parameters)
+                                               parm.FreeHandle ();
+                       base.Dispose (disposing);
+               }
+
                #endregion // Methods
        }
 }