[net_1_0] Finally all of NET_1_0 is gone from the source files
[mono.git] / mcs / class / System.Data / System.Data.Odbc / OdbcCommand.cs
index 360609708e3a36d12029dd2104a2a77df2830888..ca4f4905c9d161ec62b4401fd101d3cef933e61a 100644 (file)
@@ -34,43 +34,42 @@ using System;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
-#if NET_2_0
-using System.Data.ProviderBase;
-#endif // NET_2_0
 using System.Collections;
 using System.Runtime.InteropServices;
 
 namespace System.Data.Odbc
 {
-        /// <summary>
+       /// <summary>
        /// Represents an SQL statement or stored procedure to execute against a data source.
        /// </summary>
        [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.OdbcCommandDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
-        [ToolboxItemAttribute ("System.Drawing.Design.ToolboxItem, "+ Consts.AssemblySystem_Drawing)]
+       [ToolboxItemAttribute ("System.Drawing.Design.ToolboxItem, "+ Consts.AssemblySystem_Drawing)]
 #if NET_2_0
-       public sealed class OdbcCommand : DbCommandBase, ICloneable
+       [DefaultEvent ("RecordsAffected")]
+       public sealed class OdbcCommand : DbCommand, ICloneable
 #else
        public sealed class OdbcCommand : Component, ICloneable, IDbCommand
 #endif //NET_2_0
        {
                #region Fields
 
-#if ONLY_1_1
+               const int DEFAULT_COMMAND_TIMEOUT = 30;
+
                string commandText;
                int timeout;
                CommandType commandType;
-               UpdateRowSource updateRowSource = UpdateRowSource.Both;
-#endif // ONLY_1_1
+               UpdateRowSource updateRowSource;
 
                OdbcConnection connection;
                OdbcTransaction transaction;
                OdbcParameterCollection _parameters;
 
                bool designTimeVisible;
-               bool prepared=false;
+               bool prepared;
                IntPtr hstmt = IntPtr.Zero;
+               object generation = null; // validity of hstmt
 
-               bool disposed = false;
+               bool disposed;
                
                #endregion // Fields
 
@@ -78,21 +77,16 @@ namespace System.Data.Odbc
 
                public OdbcCommand ()
                {
-                       this.CommandText = String.Empty;
-                       this.CommandTimeout = 30; // default timeout 
-                       this.CommandType = CommandType.Text;
-                       Connection = null;
+                       timeout = DEFAULT_COMMAND_TIMEOUT;
+                       commandType = CommandType.Text;
                        _parameters = new OdbcParameterCollection ();
-                       Transaction = null;
-                       designTimeVisible = false;
-#if ONLY_1_1
+                       designTimeVisible = true;
                        updateRowSource = UpdateRowSource.Both;
-#endif // ONLY_1_1
                }
 
                public OdbcCommand (string cmdText) : this ()
                {
-                       CommandText = cmdText;
+                       commandText = cmdText;
                }
 
                public OdbcCommand (string cmdText, OdbcConnection connection)
@@ -101,8 +95,7 @@ namespace System.Data.Odbc
                        Connection = connection;
                }
 
-               public OdbcCommand (string cmdText,
-                                   OdbcConnection connection,
+               public OdbcCommand (string cmdText, OdbcConnection connection,
                                    OdbcTransaction transaction) : this (cmdText, connection)
                {
                        this.Transaction = transaction;
@@ -112,240 +105,197 @@ namespace System.Data.Odbc
 
                #region Properties
 
-               internal IntPtr hStmt
-               {
+               internal IntPtr hStmt {
                        get { return hstmt; }
                }
-               
 
-#if ONLY_1_1
-                [OdbcCategory ("Data")]
-                [DefaultValue ("")]
-                [OdbcDescriptionAttribute ("Command text to execute")]
-                [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
-                [RefreshPropertiesAttribute (RefreshProperties.All)]
-               public string CommandText 
-               {
+               [OdbcCategory ("Data")]
+               [DefaultValue ("")]
+               [OdbcDescriptionAttribute ("Command text to execute")]
+               [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
+               [RefreshPropertiesAttribute (RefreshProperties.All)]
+               public
+#if NET_2_0
+               override
+#endif
+               string CommandText {
                        get {
+                               if (commandText == null)
+                                       return string.Empty;
                                return commandText;
                        }
-                       set { 
-                               prepared=false;
-                               commandText = value;
-                       }
-               }
-
-               #else
-                [OdbcCategory ("Data")]
-                [DefaultValue ("")]
-                [OdbcDescriptionAttribute ("Command text to execute")]
-                [EditorAttribute ("Microsoft.VSDesigner.Data.Odbc.Design.OdbcCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
-                [RefreshPropertiesAttribute (RefreshProperties.All)]
-               public override string CommandText
-               {
-                       get {
-                               return base.CommandText;
-                       }
                        set {
-                               prepared=false;
-                               base.CommandText = value;
+#if NET_2_0
+                               prepared = false;
+#endif
+                               commandText = value;
                        }
                }
-#endif // ONLY_1_1
 
-#if ONLY_1_1
                [OdbcDescriptionAttribute ("Time to wait for command to execute")]
-                [DefaultValue (30)]
-               public int CommandTimeout {
-                       get {
-                               return timeout;
-                       }
+               public override
+               int CommandTimeout {
+                       get { return timeout; }
                        set {
+                               if (value < 0)
+                                       throw new ArgumentException ("The property value assigned is less than 0.",
+                                               "CommandTimeout");
                                timeout = value;
                        }
                }
 
                [OdbcCategory ("Data")]
-                [DefaultValue ("Text")]
-                [OdbcDescriptionAttribute ("How to interpret the CommandText")]
-                [RefreshPropertiesAttribute (RefreshProperties.All)]
-               public CommandType CommandType { 
-                       get {
-                               return commandType;
-                       }
+               [DefaultValue ("Text")]
+               [OdbcDescriptionAttribute ("How to interpret the CommandText")]
+               [RefreshPropertiesAttribute (RefreshProperties.All)]
+               public
+#if NET_2_0
+               override
+#endif
+               CommandType CommandType {
+                       get { return commandType; }
                        set {
+                               ExceptionHelper.CheckEnumValue (typeof (CommandType), value);
                                commandType = value;
                        }
                }
 
+#if ONLY_1_1
                [OdbcCategory ("Behavior")]
-                [OdbcDescriptionAttribute ("Connection used by the command")]
-                [DefaultValue (null)]
-                [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
-               public OdbcConnection Connection { 
-                       get {
-                               return connection;
-                       }
-                       set {
-                               connection = value;
-                       }
+               [OdbcDescriptionAttribute ("Connection used by the command")]
+               [DefaultValue (null)]
+               [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
+               public OdbcConnection Connection {
+                       get { return connection; }
+                       set { connection = value; }
                }
 #endif // ONLY_1_1
 
 #if NET_2_0
-                public new OdbcConnection Connection
-                {
-                        get { return DbConnection as OdbcConnection; }
-                        set { DbConnection = value; }
-                }
-                
+               [DefaultValue (null)]
+               [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
+               public new OdbcConnection Connection {
+                       get { return DbConnection as OdbcConnection; }
+                       set { DbConnection = value; }
+               }
 #endif // NET_2_0
 
-#if  ONLY_1_1
                [BrowsableAttribute (false)]
-                [DesignOnlyAttribute (true)]
-                [DefaultValue (true)]
-               public bool DesignTimeVisible { 
-                       get {
-                               return designTimeVisible;
-                       }
-                       set {
-                               designTimeVisible = value;
-                       }
+               [DesignOnlyAttribute (true)]
+               [DefaultValue (true)]
+#if NET_2_0
+               [EditorBrowsable (EditorBrowsableState.Never)]
+#endif
+               public
+#if NET_2_0
+               override
+#endif
+               bool DesignTimeVisible {
+                       get { return designTimeVisible; }
+                       set { designTimeVisible = value; }
                }
 
-#endif // ONLY_1_1
-
                [OdbcCategory ("Data")]
-                [OdbcDescriptionAttribute ("The parameters collection")]
-                [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
+               [OdbcDescriptionAttribute ("The parameters collection")]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Content)]
                public
 #if NET_2_0
-                new
+               new
 #endif // NET_2_0
-                OdbcParameterCollection Parameters {
+               OdbcParameterCollection Parameters {
                        get {
 #if ONLY_1_1
                                return _parameters;
-                               #else
-                                return base.Parameters as OdbcParameterCollection;
+#else
+                               return base.Parameters as OdbcParameterCollection;
 #endif // ONLY_1_1
-
                        }
                }
                
                [BrowsableAttribute (false)]
-                [OdbcDescriptionAttribute ("The transaction used by the command")]
-                [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
+               [OdbcDescriptionAttribute ("The transaction used by the command")]
+               [DesignerSerializationVisibilityAttribute (DesignerSerializationVisibility.Hidden)]
                public
 #if NET_2_0
-                new
+               new
 #endif // NET_2_0
-                OdbcTransaction Transaction {
-                       get {
-                               return transaction;
-                       }
-                       set {
-                               transaction = value;
-                       }
+               OdbcTransaction Transaction {
+                       get { return transaction; }
+                       set { transaction = value; }
                }
 
-#if ONLY_1_1
-               
                [OdbcCategory ("Behavior")]
-                [DefaultValue (UpdateRowSource.Both)]
-                [OdbcDescriptionAttribute ("When used by a DataAdapter.Update, how command results are applied to the current DataRow")]
-               public UpdateRowSource UpdatedRowSource { 
-                       [MonoTODO]
-                               get {
-                                       return updateRowSource;
-                               }
-                       [MonoTODO]
-                               set {
-                                       updateRowSource = value;
-                               }
-               }
-
-               IDbConnection IDbCommand.Connection {
-                       get {
-                               return Connection;
-                       }
+               [DefaultValue (UpdateRowSource.Both)]
+               [OdbcDescriptionAttribute ("When used by a DataAdapter.Update, how command results are applied to the current DataRow")]
+               public
+#if NET_2_0
+               override
+#endif
+               UpdateRowSource UpdatedRowSource {
+                       get { return updateRowSource; }
                        set {
-                               Connection = (OdbcConnection) value;
+                               ExceptionHelper.CheckEnumValue (typeof (UpdateRowSource), value);
+                               updateRowSource = value;
                        }
                }
-#endif // ONLY_1_1
+
 #if NET_2_0
-                protected override DbConnection DbConnection 
-                {
-                        get { return connection; }
-                        set { 
-                                connection = (OdbcConnection) value; 
-                        }                        
-                }
+               protected override DbConnection DbConnection {
+                       get { return connection; }
+                       set { connection = (OdbcConnection) value;}
+               }
 
 #endif // NET_2_0
 
 #if ONLY_1_1
-               IDataParameterCollection IDbCommand.Parameters  {
-                       get {
-                               return Parameters;
-                       }
+               IDbConnection IDbCommand.Connection {
+                       get { return Connection; }
+                       set { Connection = (OdbcConnection) value; }
+               }
+
+               IDataParameterCollection IDbCommand.Parameters {
+                       get { return Parameters; }
+               }
+#else
+               protected override DbParameterCollection DbParameterCollection {
+                       get { return _parameters as DbParameterCollection;}
                }
-               #else
-                protected override DbParameterCollection DbParameterCollection
-                {
-                        get { return _parameters as DbParameterCollection;}
-                }
-                
 #endif // NET_2_0
 
 #if ONLY_1_1
-               IDbTransaction IDbCommand.Transaction  {
-                       get {
-                               return (IDbTransaction) Transaction;
-                       }
+               IDbTransaction IDbCommand.Transaction {
+                       get { return (IDbTransaction) Transaction; }
                        set {
-                               if (value is OdbcTransaction)
-                                {
-                                        Transaction = (OdbcTransaction)value;
-                                }
-                                else
-                                {
-                                        throw new ArgumentException ();
-                                }
+                               if (value is OdbcTransaction) {
+                                       Transaction = (OdbcTransaction) value;
+                               } else {
+                                       throw new ArgumentException ();
+                               }
                        }
                }
-               #else
-               protected override DbTransaction DbTransaction 
-                {
+#else
+               protected override DbTransaction DbTransaction {
                        get { return transaction; }
-                       set {
-                                transaction = (OdbcTransaction)value;
-                       }
+                       set { transaction = (OdbcTransaction) value; }
                }
 #endif // ONLY_1_1
 
-
-
                #endregion // Properties
 
                #region Methods
 
                public
 #if NET_2_0
-                override
+               override
 #endif // NET_2_0
-                void Cancel () 
+               void Cancel ()
                {
-                       if (hstmt!=IntPtr.Zero)
-                       {
-                               OdbcReturn Ret=libodbc.SQLCancel(hstmt);
-                               if ((Ret!=OdbcReturn.Success) && (Ret!=OdbcReturn.SuccessWithInfo)) 
-                                       throw new OdbcException(new OdbcError("SQLCancel",OdbcHandleType.Stmt,hstmt));
-                       }
-                       else
-                               throw new InvalidOperationException();
+                       if (hstmt != IntPtr.Zero) {
+                               OdbcReturn Ret = libodbc.SQLCancel (hstmt);
+                               if (Ret != OdbcReturn.Success && Ret != OdbcReturn.SuccessWithInfo)
+                                       throw connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
+                       } else
+                               throw new InvalidOperationException ();
                }
 
 #if ONLY_1_1
@@ -354,75 +304,105 @@ namespace System.Data.Odbc
                        return CreateParameter ();
                }
 
-               public OdbcParameter CreateParameter ()
+#else
+               protected override DbParameter CreateDbParameter ()
                {
-                       return new OdbcParameter ();
+                       return CreateParameter ();
                }
-               #else
-                protected override DbParameter CreateDbParameter ()
-                {
-                        return CreateParameter ();
-                }
-                
 #endif // ONLY_1_1
 
-               
+               public new OdbcParameter CreateParameter ()
+               {
+                       return new OdbcParameter ();
+               }
+
+               internal void Unlink ()
+               {
+                       if (disposed)
+                               return;
+
+                       FreeStatement (false);
+               }
+
                protected override void Dispose (bool disposing)
                {
                        if (disposed)
                                return;
-                       
+
                        FreeStatement (); // free handles
+#if NET_2_0
+                       CommandText = null;
+#endif
                        Connection = null;
                        Transaction = null;
+                       Parameters.Clear ();
                        disposed = true;
                }
 
-               ~OdbcCommand ()
-               {
-                       Dispose (false);
-               }
-
                private IntPtr ReAllocStatment ()
                {
                        OdbcReturn ret;
 
                        if (hstmt != IntPtr.Zero)
+                               // Free the existing hstmt.  Also unlinks from the connection.
                                FreeStatement ();
-
-                       ret=libodbc.SQLAllocHandle(OdbcHandleType.Stmt, Connection.hDbc, ref hstmt);
-                       if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo)) 
-                               throw new OdbcException(new OdbcError("SQLAllocHandle",OdbcHandleType.Dbc,Connection.hDbc));
+                       // Link this command to the connection.  The hstmt created below
+                       // only remains valid while generation == Connection.generation.
+                       generation = Connection.Link (this);
+                       ret = libodbc.SQLAllocHandle (OdbcHandleType.Stmt, Connection.hDbc, ref hstmt);
+                       if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
+                               throw connection.CreateOdbcException (OdbcHandleType.Dbc, Connection.hDbc);
                        disposed = false;
                        return hstmt;
                }
 
-               private void FreeStatement ()
+               void FreeStatement ()
                {
+                       FreeStatement (true);
+               }
+
+               private void FreeStatement (bool unlink)
+               {
+                       prepared = false;
+
                        if (hstmt == IntPtr.Zero)
                                return;
+
+                       // Normally the command is unlinked from the connection, but during
+                       // OdbcConnection.Close() this would be pointless and (quadratically)
+                       // slow.
+                       if (unlink)
+                               Connection.Unlink (this);
+
+                       // Serialize with respect to the connection's own destruction
+                       lock(Connection) {
+                               // If the connection has already called SQLDisconnect then hstmt
+                               // may have already been freed, in which case it is not safe to
+                               // use.  Thus the generation check.
+                               if(Connection.Generation == generation) {
+                                       // free previously allocated handle.
+                                       OdbcReturn ret = libodbc.SQLFreeStmt (hstmt, libodbc.SQLFreeStmtOptions.Close);
+                                       if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
+                                               throw connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
                        
-                       // free previously allocated handle.
-                       OdbcReturn ret = libodbc.SQLFreeStmt (hstmt, libodbc.SQLFreeStmtOptions.Close);
-                       if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo)) 
-                               throw new OdbcException(new OdbcError("SQLCloseCursor",OdbcHandleType.Stmt,hstmt));
-                       
-                       ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, hstmt);
-                       if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo)) 
-                               throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,hstmt));
-                       hstmt = IntPtr.Zero;
+                                       ret = libodbc.SQLFreeHandle ((ushort) OdbcHandleType.Stmt, hstmt);
+                                       if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
+                                               throw connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
+                               }
+                               hstmt = IntPtr.Zero;
+                       }
                }
                
-               private void ExecSQL(string sql)
+               private void ExecSQL (CommandBehavior behavior, bool createReader, string sql)
                {
                        OdbcReturn ret;
-                       if (! prepared && Parameters.Count <= 0) {
 
+                       if (!prepared && Parameters.Count == 0) {
                                ReAllocStatment ();
-                               
-                               ret=libodbc.SQLExecDirect(hstmt, sql, sql.Length);
-                               if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo)) 
-                                       throw new OdbcException(new OdbcError("SQLExecDirect",OdbcHandleType.Stmt,hstmt));
+
+                               ret = libodbc.SQLExecDirect (hstmt, sql, libodbc.SQL_NTS);
+                               if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo && ret != OdbcReturn.NoData)
+                                       throw connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
                                return;
                        }
 
@@ -430,9 +410,9 @@ namespace System.Data.Odbc
                                Prepare();
 
                        BindParameters ();
-                       ret=libodbc.SQLExecute(hstmt);
-                       if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo)) 
-                               throw new OdbcException(new OdbcError("SQLExecute",OdbcHandleType.Stmt,hstmt));
+                       ret = libodbc.SQLExecute (hstmt);
+                       if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
+                               throw connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
                }
 
                internal void FreeIfNotPrepared ()
@@ -443,39 +423,41 @@ namespace System.Data.Odbc
 
                public
 #if NET_2_0
-                override
+               override
 #endif // NET_2_0
-                int ExecuteNonQuery ()
+               int ExecuteNonQuery ()
                {
-                       return ExecuteNonQuery (true);
+                       return ExecuteNonQuery ("ExecuteNonQuery", CommandBehavior.Default, false);
                }
 
-               private int ExecuteNonQuery (bool freeHandle) 
+               private int ExecuteNonQuery (string method, CommandBehavior behavior, bool createReader)
                {
                        int records = 0;
                        if (Connection == null)
-                               throw new InvalidOperationException ();
+                               throw new InvalidOperationException (string.Format (
+                                       "{0}: Connection is not set.", method));
                        if (Connection.State == ConnectionState.Closed)
-                               throw new InvalidOperationException ();
-                       // FIXME: a third check is mentioned in .NET docs
+                               throw new InvalidOperationException (string.Format (
+                                       "{0}: Connection state is closed", method));
+                       if (CommandText.Length == 0)
+                               throw new InvalidOperationException (string.Format (
+                                       "{0}: CommandText is not set.", method));
 
-                       ExecSQL(CommandText);
+                       ExecSQL (behavior, createReader, CommandText);
 
                        // .NET documentation says that except for INSERT, UPDATE and
-                        // DELETE  where the return value is the number of rows affected
-                        // for the rest of the commands the return value is -1.
-                        if ((CommandText.ToUpper().IndexOf("UPDATE")!=-1) ||
+                       // DELETE  where the return value is the number of rows affected
+                       // for the rest of the commands the return value is -1.
+                       if ((CommandText.ToUpper().IndexOf("UPDATE")!=-1) ||
                            (CommandText.ToUpper().IndexOf("INSERT")!=-1) ||
                            (CommandText.ToUpper().IndexOf("DELETE")!=-1)) {
-                                                                                                    
                                int numrows = 0;
-                               OdbcReturn ret = libodbc.SQLRowCount(hstmt,ref numrows);
+                               libodbc.SQLRowCount (hstmt, ref numrows);
                                records = numrows;
-                        }
-                        else
+                       } else
                                records = -1;
 
-                       if (freeHandle && !prepared)
+                       if (!createReader && !prepared)
                                FreeStatement ();
                        
                        return records;
@@ -483,36 +465,34 @@ namespace System.Data.Odbc
 
                public
 #if NET_2_0
-                override
+               override
 #endif // NET_2_0
-                void Prepare()
+               void Prepare()
                {
                        ReAllocStatment ();
                        
                        OdbcReturn ret;
-                       ret=libodbc.SQLPrepare(hstmt, CommandText, CommandText.Length);
-                       if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo)) 
-                               throw new OdbcException(new OdbcError("SQLPrepare",OdbcHandleType.Stmt,hstmt));
-                       prepared=true;
+                       ret = libodbc.SQLPrepare(hstmt, CommandText, CommandText.Length);
+                       if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
+                               throw connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
+                       prepared = true;
                }
 
                private void BindParameters ()
                {
-                       int i=1;
-                       foreach (OdbcParameter p in Parameters)
-                       {
-                               p.Bind(hstmt, i);
+                       int i = 1;
+                       foreach (OdbcParameter p in Parameters) {
+                               p.Bind (this, hstmt, i);
                                p.CopyValue ();
                                i++;
                        }
                }
 
-
                public
 #if NET_2_0
-                new
+               new
 #endif // NET_2_0
-                OdbcDataReader ExecuteReader ()
+               OdbcDataReader ExecuteReader ()
                {
                        return ExecuteReader (CommandBehavior.Default);
                }
@@ -522,63 +502,71 @@ namespace System.Data.Odbc
                {
                        return ExecuteReader ();
                }
-               #else
-                protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
-                {
-                        return ExecuteReader (behavior);
-                }
-                
+#else
+               protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
+               {
+                       return ExecuteReader (behavior);
+               }
 #endif // ONLY_1_1
 
                public
 #if NET_2_0
-                new
+               new
 #endif // NET_2_0
-                OdbcDataReader ExecuteReader (CommandBehavior behavior)
+               OdbcDataReader ExecuteReader (CommandBehavior behavior)
                {
-                       int recordsAffected = ExecuteNonQuery(false);
-                       OdbcDataReader dataReader=new OdbcDataReader(this, behavior, recordsAffected);
+                       return ExecuteReader ("ExecuteReader", behavior);
+               }
+
+               OdbcDataReader ExecuteReader (string method, CommandBehavior behavior)
+               {
+                       int recordsAffected = ExecuteNonQuery (method, behavior, true);
+                       OdbcDataReader dataReader = new OdbcDataReader (this, behavior, recordsAffected);
                        return dataReader;
                }
 
 #if ONLY_1_1
-                IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
+               IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
                {
                        return ExecuteReader (behavior);
                }
 #endif // ONLY_1_1
 
-#if ONLY_1_1
-               public object ExecuteScalar ()
+               public
+#if NET_2_0
+               override
+#endif
+               object ExecuteScalar ()
                {
                        object val = null;
-                       OdbcDataReader reader=ExecuteReader();
-                       try
-                       {
+                       OdbcDataReader reader = ExecuteReader ("ExecuteScalar",
+                               CommandBehavior.Default);
+                       try {
                                if (reader.Read ())
-                                       val=reader[0];
-                       }
-                       finally
-                       {
-                               reader.Close();
+                                       val = reader [0];
+                       } finally {
+                               reader.Close ();
                        }
                        return val;
                }
-#endif // ONLY_1_1
 
-               [MonoTODO]
                object ICloneable.Clone ()
                {
-                       throw new NotImplementedException ();   
-               }
-
-               public 
-#if NET_2_0
-                override
-#endif // NET_2_0
-                void ResetCommandTimeout ()
+                       OdbcCommand command = new OdbcCommand ();
+                       command.CommandText = this.CommandText;
+                       command.CommandTimeout = this.CommandTimeout;
+                       command.CommandType = this.CommandType;
+                       command.Connection = this.Connection;
+                       command.DesignTimeVisible = this.DesignTimeVisible;
+                       foreach (OdbcParameter parameter in this.Parameters)
+                               command.Parameters.Add (parameter);
+                       command.Transaction = this.Transaction;
+                       return command;
+               }
+
+               public void ResetCommandTimeout ()
                {
-                       CommandTimeout = 30;
+                       CommandTimeout = DEFAULT_COMMAND_TIMEOUT;
                }
 
                #endregion