2002-11-26 Tim Coleman <tim@timcoleman.com>
authorTim Coleman <tim@mono-cvs.ximian.com>
Tue, 26 Nov 2002 06:36:05 +0000 (06:36 -0000)
committerTim Coleman <tim@mono-cvs.ximian.com>
Tue, 26 Nov 2002 06:36:05 +0000 (06:36 -0000)
        * Mono.Data.TdsClient.build:
        * makefile.gnu
                Add System.EnterpriseServices to build.
        * Mono.Data.TdsClient/TdsCommand.cs:
        * Mono.Data.TdsClient/TdsConnection.cs:
        * Mono.Data.TdsClient/TdsDataReader.cs:
        * Mono.Data.TdsClient/TdsException.cs:
        * Mono.Data.TdsClient/TdsParameter.cs:
        * Mono.Data.TdsClient/TdsParameterCollection.cs:
        * Mono.Data.TdsClient/TdsTransaction.cs:
        * Mono.Data.TdsTypes/TdsDecimal.cs:
                Copied over from the Sybase classes because the
                whole world is changing and I want generic
                TDS to keep up.

svn path=/trunk/mcs/; revision=9194

mcs/class/Mono.Data.TdsClient/ChangeLog
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient.build
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient/TdsCommand.cs
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient/TdsConnection.cs
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient/TdsDataReader.cs
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient/TdsException.cs
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient/TdsParameter.cs
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient/TdsParameterCollection.cs
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsClient/TdsTransaction.cs
mcs/class/Mono.Data.TdsClient/Mono.Data.TdsTypes/TdsDecimal.cs
mcs/class/Mono.Data.TdsClient/makefile.gnu

index e2dfb0f6eefc9c5180a09da9532f4c895712ceed..600709aa332ff8b481eb4be7db4ac7fe634e754d 100644 (file)
@@ -1,3 +1,19 @@
+2002-11-26  Tim Coleman <tim@timcoleman.com>
+       * Mono.Data.TdsClient.build:
+       * makefile.gnu
+               Add System.EnterpriseServices to build.
+       * Mono.Data.TdsClient/TdsCommand.cs:
+       * Mono.Data.TdsClient/TdsConnection.cs:
+       * Mono.Data.TdsClient/TdsDataReader.cs:
+       * Mono.Data.TdsClient/TdsException.cs:
+       * Mono.Data.TdsClient/TdsParameter.cs:
+       * Mono.Data.TdsClient/TdsParameterCollection.cs:
+       * Mono.Data.TdsClient/TdsTransaction.cs:
+       * Mono.Data.TdsTypes/TdsDecimal.cs:
+               Copied over from the Sybase classes because the
+               whole world is changing and I want generic
+               TDS to keep up.
+
 2002-11-21  Tim Coleman <tim@timcoleman.com>
        * Mono.Data.TdsClient.build:
        * Mono.Data.TdsClient/TdsCommand.cs:
index 5e203aae4738badfdcee7f6f9d1e1946289159c1..deec8da52f6d9ebbe5365501147d6d8677d23f1c 100644 (file)
@@ -15,6 +15,7 @@
                        <arg value="/unsafe"/>\r
                        <arg value="/noconfig"/>\r
                        <arg value="/r:System.dll"/>\r
+                       <arg value="/r:System.EnterpriseServices.dll"/>\r
                        <arg value="/r:System.Xml.dll"/>\r
                        <arg value="/r:System.Data.dll"/>\r
                        <arg value="/r:../lib/Mono.Data.Tds.dll"/>\r
@@ -28,6 +29,7 @@
                        <references>\r
                                <includes name="../lib/corlib.dll"/>\r
                                <includes name="../lib/System.dll"/>\r
+                               <includes name="../lib/System.EnterpriseServices.dll"/>\r
                                <includes name="../lib/System.Xml.dll"/>\r
                                <includes name="../lib/System.Data.dll"/>\r
                                <includes name="../lib/Mono.Data.Tds.dll"/>\r
index f25c7c663583d9db9c56cbbd0969fc2580f111d0..f01591bc9302be81faceeadcf910d834971f32a7 100644 (file)
 // Mono.Data.TdsClient.TdsCommand.cs
 //
 // Author:
+//   Rodrigo Moya (rodrigo@ximian.com)
+//   Daniel Morgan (danmorg@sc.rr.com)
 //   Tim Coleman (tim@timcoleman.com)
 //
-// Copyright (C) 2002 Tim Coleman
+// (C) Ximian, Inc 2002 http://www.ximian.com/
+// (C) Daniel Morgan, 2002
+// Copyright (C) Tim Coleman, 2002
 //
 
+using Mono.Data.Tds;
 using Mono.Data.Tds.Protocol;
 using System;
+using System.Collections;
+using System.Collections.Specialized;
 using System.ComponentModel;
 using System.Data;
+using System.Data.Common;
+using System.Runtime.InteropServices;
+using System.Text;
 
 namespace Mono.Data.TdsClient {
-        public class TdsCommand : Component, ICloneable, IDbCommand
+       public sealed class TdsCommand : Component, IDbCommand, ICloneable
        {
                #region Fields
 
-               string commandText;
+               bool disposed = false;
                int commandTimeout;
+               bool designTimeVisible;
+               string commandText;
                CommandType commandType;
                TdsConnection connection;
-               TdsParameterCollection parameters;
                TdsTransaction transaction;
+               UpdateRowSource updatedRowSource;
+               CommandBehavior behavior = CommandBehavior.Default;
+               TdsParameterCollection parameters;
 
                #endregion // Fields
 
                #region Constructors
 
-               public TdsCommand ()
+               public TdsCommand() 
                        : this (String.Empty, null, null)
                {
                }
 
-               public TdsCommand (string commandText)
+               public TdsCommand (string commandText) 
                        : this (commandText, null, null)
                {
+                       commandText = commandText;
                }
 
-               public TdsCommand (string commandText, TdsConnection connection)
+               public TdsCommand (string commandText, TdsConnection connection) 
                        : this (commandText, connection, null)
                {
+                       Connection = connection;
                }
 
-               public TdsCommand (string commandText, TdsConnection connection, TdsTransaction transaction)
+               public TdsCommand (string commandText, TdsConnection connection, TdsTransaction transaction) 
                {
                        this.commandText = commandText;
+                       this.connection = connection;
                        this.transaction = transaction;
                        this.commandType = CommandType.Text;
-                       this.connection = connection;
+                       this.updatedRowSource = UpdateRowSource.Both;
+
+                       this.designTimeVisible = false;
+                       this.commandTimeout = 30;
+                       parameters = new TdsParameterCollection (this);
                }
 
                #endregion // Constructors
 
                #region Properties
 
+               internal CommandBehavior CommandBehavior {
+                       get { return behavior; }
+               }
+
                public string CommandText {
                        get { return commandText; }
                        set { commandText = value; }
                }
 
                public int CommandTimeout {
-                       get { return commandTimeout; }
-                       set { commandTimeout = value; }
+                       get { return commandTimeout;  }
+                       set { 
+                               if (commandTimeout < 0)
+                                       throw new ArgumentException ("The property value assigned is less than 0.");
+                               commandTimeout = value; 
+                       }
                }
 
-               public CommandType CommandType {
+               public CommandType CommandType  {
                        get { return commandType; }
-                       set { commandType = value; }
+                       set { 
+                               if (value == CommandType.TableDirect)
+                                       throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono TdsClient Data Provider.");
+                               commandType = value; 
+                       }
                }
 
-               public TdsConnection Connection {       
+               public TdsConnection Connection {
                        get { return connection; }
                        set { 
                                if (transaction != null && connection.Transaction != null && connection.Transaction.IsOpen)
                                        throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress.");
                                transaction = null;
-                               connection = value;
+                               connection = value; 
                        }
                }
 
+               public bool DesignTimeVisible {
+                       get { return designTimeVisible; } 
+                       set { designTimeVisible = value; }
+               }
+
+               public TdsParameterCollection Parameters {
+                       get { return parameters; }
+               }
+
+               internal ITds Tds {
+                       get { return Connection.Tds; }
+               }
+
                IDbConnection IDbCommand.Connection {
                        get { return Connection; }
                        set { 
-                               if (!(value is TdsConnection)) 
-                                       throw new ArgumentException ();
-                               Connection = (TdsConnection) value;     
+                               if (!(value is TdsConnection))
+                                       throw new InvalidCastException ("The value was not a valid TdsConnection.");
+                               Connection = (TdsConnection) value;
                        }
                }
 
-               IDataParameterCollection IDbCommand.Parameters {
+               IDataParameterCollection IDbCommand.Parameters  {
                        get { return Parameters; }
                }
 
                IDbTransaction IDbCommand.Transaction {
                        get { return Transaction; }
                        set { 
-                               if (!(value is TdsTransaction)) 
+                               if (!(value is TdsTransaction))
                                        throw new ArgumentException ();
                                Transaction = (TdsTransaction) value; 
                        }
                }
 
-               public TdsParameterCollection Parameters {
-                       get { return parameters; }
-               }
-
-               internal ITds Tds {
-                       get { return connection.Tds; }
-               }
-
                public TdsTransaction Transaction {
                        get { return transaction; }
                        set { transaction = value; }
+               }       
+
+               public UpdateRowSource UpdatedRowSource {
+                       get { return updatedRowSource; }
+                       set { updatedRowSource = value; }
                }
 
-               [MonoTODO]
-               public UpdateRowSource UpdatedRowSource {
-                       get { throw new NotImplementedException (); }
-                       set { throw new NotImplementedException (); }
+               #endregion // Fields
+
+               #region Methods
+
+               public void Cancel () 
+               {
+                       if (Connection == null || Connection.Tds == null)
+                               return;
+                       Connection.Tds.Cancel ();
                }
 
-               #endregion // Properties
+               internal void CloseDataReader (bool moreResults)
+               {
+                       GetOutputParameters ();
+                       Connection.DataReader = null;
+
+                       if ((behavior & CommandBehavior.CloseConnection) != 0)
+                               Connection.Close ();
+               }
 
-                #region Methods
+               public TdsParameter CreateParameter () 
+               {
+                       return new TdsParameter ();
+               }
 
-               [MonoTODO]
-               public void Cancel ()
+               internal void DeriveParameters ()
                {
-                       throw new NotImplementedException ();
+                       if (commandType != CommandType.StoredProcedure)
+                               throw new InvalidOperationException (String.Format ("TdsCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
+                       ValidateCommand ("DeriveParameters");
+
+                       TdsParameterCollection localParameters = new TdsParameterCollection (this);
+                       localParameters.Add ("@P1", TdsType.NVarChar, commandText.Length).Value = commandText;
+
+                       string sql = "sp_procedure_params_rowset";
+
+                       Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true);
+
+                       TdsDataReader reader = new TdsDataReader (this);
+                       parameters.Clear ();
+                       object[] dbValues = new object[reader.FieldCount];
+
+                       while (reader.Read ()) {
+                               reader.GetValues (dbValues);
+                               parameters.Add (new TdsParameter (dbValues));
+                       }
+                       reader.Close ();        
                }
 
-               [MonoTODO]
-               TdsParameter CreateParameter ()
+               private void Execute (CommandBehavior behavior, bool wantResults)
                {
-                       throw new NotImplementedException ();
+                       TdsMetaParameterCollection parms = Parameters.MetaParameters;
+                       bool schemaOnly = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
+                       bool keyInfo = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
+
+                       StringBuilder sql1 = new StringBuilder ();
+                       StringBuilder sql2 = new StringBuilder ();
+
+                       if (schemaOnly || keyInfo)
+                               sql1.Append ("SET FMTONLY OFF;");
+                       if (keyInfo) {
+                               sql1.Append ("SET NO_BROWSETABLE ON;");
+                               sql2.Append ("SET NO_BROWSETABLE OFF;");
+                       }
+                       if (schemaOnly) {
+                               sql1.Append ("SET FMTONLY ON;");
+                               sql2.Append ("SET FMTONLY OFF;");
+                       }
+
+                       switch (CommandType) {
+                       case CommandType.StoredProcedure:
+                               if (keyInfo || schemaOnly)
+                                       Connection.Tds.Execute (sql1.ToString ());
+                               Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults);
+                               if (keyInfo || schemaOnly)
+                                       Connection.Tds.Execute (sql2.ToString ());
+                               break;
+                       case CommandType.Text:
+                               string sql = String.Format ("{0}{1}{2}", sql1.ToString (), CommandText, sql2.ToString ());
+                               Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults);
+                               break;
+                       }
                }
 
                public int ExecuteNonQuery ()
                {
                        ValidateCommand ("ExecuteNonQuery");
-                       return connection.Tds.ExecuteNonQuery (FormatQuery (commandText, commandType));
+                       int result = 0;
+
+                       try {
+                               Execute (CommandBehavior.Default, false);
+                       }
+                       catch (TdsTimeoutException e) {
+                               throw TdsException.FromTdsInternalException ((TdsInternalException) e);
+                       }
+
+                       GetOutputParameters ();
+                       return result;
                }
 
                public TdsDataReader ExecuteReader ()
@@ -151,34 +266,57 @@ namespace Mono.Data.TdsClient {
                public TdsDataReader ExecuteReader (CommandBehavior behavior)
                {
                        ValidateCommand ("ExecuteReader");
-                       connection.DataReader = new TdsDataReader (this);
-                       return connection.DataReader;
+                       try {
+                               Execute (behavior, true);
+                       }
+                       catch (TdsTimeoutException e) {
+                               throw TdsException.FromTdsInternalException ((TdsInternalException) e);
+                       }
+                       Connection.DataReader = new TdsDataReader (this);
+                       return Connection.DataReader;
                }
 
-               [MonoTODO]
                public object ExecuteScalar ()
                {
-                       throw new NotImplementedException ();
+                       ValidateCommand ("ExecuteScalar");
+                       try {
+                               Execute (CommandBehavior.Default, true);
+                       }
+                       catch (TdsTimeoutException e) {
+                               throw TdsException.FromTdsInternalException ((TdsInternalException) e);
+                       }
+
+                       if (!Connection.Tds.NextResult () || !Connection.Tds.NextRow ())
+                               return null;
+
+                       object result = Connection.Tds.ColumnValues [0];
+                       CloseDataReader (true);
+                       return result;
                }
 
-               private static string FormatQuery (string commandText, CommandType commandType)
+               private void GetOutputParameters ()
                {
-                       switch (commandType) {
-                       case CommandType.Text :
-                               return commandText;
-                       case CommandType.TableDirect :
-                               return String.Format ("select * from {0}", commandText);
-                       case CommandType.StoredProcedure :
-                               return String.Format ("exec {0}", commandText);
+                       Connection.Tds.SkipToEnd ();
+
+                       IList list = Connection.Tds.ColumnValues;
+
+                       if (list != null && list.Count > 0) {
+                               int index = 0;
+                               foreach (TdsParameter parameter in parameters) {
+                                       if (parameter.Direction != ParameterDirection.Input) {
+                                               parameter.Value = list [index];
+                                               index += 1;
+                                       }
+                                       if (index >= list.Count)
+                                               break;
+                               }
                        }
-                       throw new InvalidOperationException ("Invalid command type");
                }
 
-               [MonoTODO]
-                object ICloneable.Clone()
-                {
-                        throw new NotImplementedException ();
-                }
+               object ICloneable.Clone ()
+               {
+                       return new TdsCommand (commandText, Connection);
+               }
 
                IDbDataParameter IDbCommand.CreateParameter ()
                {
@@ -195,26 +333,30 @@ namespace Mono.Data.TdsClient {
                        return ExecuteReader (behavior);
                }
 
-               [MonoTODO]
                public void Prepare ()
                {
-                       throw new NotImplementedException ();
+                       throw new NotSupportedException ("TdsClient does not support PREPARE.");
+               }
+
+               public void ResetCommandTimeout ()
+               {
+                       commandTimeout = 30;
                }
 
                private void ValidateCommand (string method)
                {
-                       if (connection == null)
+                       if (Connection == null)
                                throw new InvalidOperationException (String.Format ("{0} requires a Connection object to continue.", method));
-                       if (connection.Transaction != null && transaction != connection.Transaction)
+                       if (Connection.Transaction != null && transaction != Connection.Transaction)
                                throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object.");
-                       if (connection.State != ConnectionState.Open)
+                       if (Connection.State != ConnectionState.Open)
                                throw new InvalidOperationException (String.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method));
                        if (commandText == String.Empty || commandText == null)
                                throw new InvalidOperationException ("The command text for this Command has not been set.");
-                       if (connection.DataReader != null)
+                       if (Connection.DataReader != null)
                                throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
                }
 
-                #endregion // Methods
+               #endregion // Methods
        }
 }
index d8e9bf51d918530960b84d8a6873317662e50e4c..66a554dc954a0394f7cccdc6cfe995bc2b624040 100644 (file)
@@ -4,7 +4,7 @@
 // Author:
 //   Tim Coleman (tim@timcoleman.com)
 //
-// Copyright (C) 2002 Tim Coleman
+// Copyright (C) Tim Coleman, 2002
 //
 
 using Mono.Data.Tds.Protocol;
@@ -13,82 +13,76 @@ using System.Collections;
 using System.Collections.Specialized;
 using System.ComponentModel;
 using System.Data;
+using System.Data.Common;
+using System.EnterpriseServices;
 using System.Net;
 using System.Text;
 
 namespace Mono.Data.TdsClient {
-        public class TdsConnection : Component, ICloneable, IDbConnection
+       public sealed class TdsConnection : Component, IDbConnection, ICloneable        
        {
                #region Fields
+               bool disposed = false;
 
-               public static readonly string LibraryName = "Mono.Data.TdsClient";
+               // The set of SQL connection pools
+               static Hashtable TdsConnectionPools = new Hashtable ();
 
-               string dataSource;    // the database server name
-               int port;             // which port to use
-               int packetSize = 512; // what size are the packets we send/receive?
-               bool connectionReset;
-               bool pooling;
-               int minPoolSize;
-               int maxPoolSize;
+               // The current connection pool
+               TdsConnectionPool pool;
 
+               // The connection string that identifies this connection
                string connectionString = null;
 
-               int connectionTimeout = 15;
-               IsolationLevel isolationLevel = IsolationLevel.ReadCommitted;
-
-               ConnectionState state = ConnectionState.Closed;
-               TdsConnectionParameters parms = new TdsConnectionParameters ();
+               // The transaction object for the current transaction
                TdsTransaction transaction = null;
 
-               // This is the collection of connection pools available
-               static Hashtable pools = new Hashtable ();
-               TdsConnectionPool pool;
+               // Connection parameters
+               TdsConnectionParameters parms = new TdsConnectionParameters ();
+               bool connectionReset;
+               bool pooling;
+               string dataSource;
+               int connectionTimeout;
+               int minPoolSize;
+               int maxPoolSize;
+               int packetSize;
+               int port = 1533;
 
-               // Our TDS object, the real workhorse
-               ITds tds = null;
+               // The current state
+               ConnectionState state = ConnectionState.Closed;
 
                TdsDataReader dataReader = null;
 
-               static readonly object EventTdsInfoMessage = new object ();
-               static readonly object EventStateChange = new object ();
+               // The TDS object
+               ITds tds;
 
                #endregion // Fields
 
                #region Constructors
 
-               public TdsConnection ()
-                       : this (String.Empty, 1433)
+               public TdsConnection () 
+                       : this (String.Empty)
                {
                }
-
-               public TdsConnection (string connectionString)
-                       : this (connectionString, 1433)
+       
+               public TdsConnection (string connectionString) 
                {
+                       ConnectionString = connectionString;
                }
 
-               public TdsConnection (string connectionString, int port)
-               {
-                       this.port = port;
-                       parms.User = null;
-                       parms.Password = null;
-                       parms.LibraryName = LibraryName;
-                       SetConnectionString (connectionString);
-               }
-                       
                #endregion // Constructors
 
                #region Properties
-
-               public string ConnectionString {
+               
+               public string ConnectionString  {
                        get { return connectionString; }
                        set { SetConnectionString (value); }
                }
-
+               
                public int ConnectionTimeout {
                        get { return connectionTimeout; }
                }
 
-               public string Database {
+               public string Database  {
                        get { return tds.Database; }
                }
 
@@ -98,66 +92,52 @@ namespace Mono.Data.TdsClient {
                }
 
                public string DataSource {
-                       get { return DataSource; }
+                       get { return dataSource; }
                }
 
                public int PacketSize {
-                       get { return PacketSize; }
+                       get { return packetSize; }
                }
 
                public string ServerVersion {
-                       get {
-                               if (state == ConnectionState.Closed)
-                                       throw new InvalidOperationException ();
-                               return tds.ServerVersion; 
-                       }
+                       get { return tds.ServerVersion; }
                }
 
                public ConnectionState State {
                        get { return state; }
                }
-               
+
                internal ITds Tds {
                        get { return tds; }
                }
 
-               internal TdsTransaction Transaction {   
+               internal TdsTransaction Transaction {
                        get { return transaction; }
+                       set { transaction = value; }
                }
-       
+
                public string WorkstationId {
                        get { return parms.Hostname; }
                }
 
                #endregion // Properties
-               
-               #region Events
-
-               public event TdsInfoMessageEventHandler InfoMessage {
-                       add { Events.AddHandler (EventTdsInfoMessage, value); }
-                       remove { Events.RemoveHandler (EventTdsInfoMessage, value); }
-               }
-
-               public event StateChangeEventHandler StateChange {
-                       add { Events.AddHandler (EventStateChange, value); }
-                       remove { Events.RemoveHandler (EventStateChange, value); }
-               }
-
-               #endregion // Events
-
-               #region Delegates
 
+               #region Events and Delegates
+                
+               public event TdsInfoMessageEventHandler InfoMessage;
+               public event StateChangeEventHandler StateChange;
+               
                private void ErrorHandler (object sender, TdsInternalErrorMessageEventArgs e)
                {
                        throw new TdsException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono TdsClient Data Provider", e.State);
-               } 
+               }
 
                private void MessageHandler (object sender, TdsInternalInfoMessageEventArgs e)
                {
                        OnTdsInfoMessage (CreateTdsInfoMessageEvent (e.Errors));
                }
 
-               #endregion // Delegates
+               #endregion // Events and Delegates
 
                #region Methods
 
@@ -178,22 +158,42 @@ namespace Mono.Data.TdsClient {
 
                public TdsTransaction BeginTransaction (IsolationLevel iso, string transactionName)
                {
-                       if (state == ConnectionState.Closed)
-                               throw new InvalidOperationException ("Invalid operation. The connection is closed.");
-                       if (transaction != null && transaction.IsOpen)
+                       if (State == ConnectionState.Closed)
+                               throw new InvalidOperationException ("The connection is not open.");
+                       if (Transaction != null)
                                throw new InvalidOperationException ("TdsConnection does not support parallel transactions.");
-                       tds.ExecuteNonQuery (String.Format ("BEGIN TRANSACTION {0}", transactionName));
+
+                       string isolevel = String.Empty;
+                       switch (iso) {
+                       case IsolationLevel.Chaos:
+                               isolevel = "CHAOS";
+                               break;
+                       case IsolationLevel.ReadCommitted:
+                               isolevel = "READ COMMITTED";
+                               break;
+                       case IsolationLevel.ReadUncommitted:
+                               isolevel = "READ UNCOMMITTED";
+                               break;
+                       case IsolationLevel.RepeatableRead:
+                               isolevel = "REPEATABLE READ";
+                               break;
+                       case IsolationLevel.Serializable:
+                               isolevel = "SERIALIZABLE";
+                               break;
+                       }
+
+                       tds.Execute (String.Format ("SET TRANSACTION ISOLATION LEVEL {0}\nBEGIN TRANSACTION {1}", isolevel, transactionName));
                        transaction = new TdsTransaction (this, iso);
                        return transaction;
                }
 
-               public void ChangeDatabase (string database)
+               public void ChangeDatabase (string database) 
                {
                        if (!IsValidDatabaseName (database))
-                               throw new ArgumentException (String.Format ("The database name {0} is not valid.", database));
-                       if (Database == database)
-                               return;
-                       tds.ExecuteNonQuery (String.Format ("use {0}", database));
+                               throw new ArgumentException (String.Format ("The database name {0} is not valid."));
+                       if (State != ConnectionState.Open)
+                               throw new InvalidOperationException ("The connection is not open");
+                       tds.Execute (String.Format ("use {0}", database));
                }
 
                private void ChangeState (ConnectionState currentState)
@@ -203,61 +203,69 @@ namespace Mono.Data.TdsClient {
                        OnStateChange (CreateStateChangeEvent (originalState, currentState));
                }
 
-               public void Close ()
+               public void Close () 
                {
-                       // rollback any open transactions
-                       if (transaction != null && transaction.IsOpen)
-                               transaction.Rollback ();
-
-                       // if we aren't pooling, just close the connection
-                       // otherwise, relinquish the lock that we established in
-                       // the connection pool.
+                       if (Transaction != null && Transaction.IsOpen)
+                               Transaction.Rollback ();
                        if (pooling)
                                pool.ReleaseConnection (tds);
                        else
                                tds.Disconnect ();
-
                        tds.TdsErrorMessage -= new TdsInternalErrorMessageEventHandler (ErrorHandler);
                        tds.TdsInfoMessage -= new TdsInternalInfoMessageEventHandler (MessageHandler);
                        ChangeState (ConnectionState.Closed);
                }
 
-               [MonoTODO]
-               protected override void Dispose (bool disposing)
-               {
-                       Close ();
-               }
-
-               public TdsCommand CreateCommand ()
+               public TdsCommand CreateCommand () 
                {
                        TdsCommand command = new TdsCommand ();
                        command.Connection = this;
                        return command;
                }
 
+               private StateChangeEventArgs CreateStateChangeEvent (ConnectionState originalState, ConnectionState currentState)
+               {
+                       return new StateChangeEventArgs (originalState, currentState);
+               }
+
                private TdsInfoMessageEventArgs CreateTdsInfoMessageEvent (TdsInternalErrorCollection errors)
                {
                        return new TdsInfoMessageEventArgs (errors);
                }
 
-               private StateChangeEventArgs CreateStateChangeEvent (ConnectionState originalState, ConnectionState currentState)
+               protected override void Dispose (bool disposing)
                {
-                       return new StateChangeEventArgs (originalState, currentState);
+                       if (!disposed) {
+                               if (disposing) {
+                                       if (State == ConnectionState.Open)
+                                               Close ();
+                                       parms = null;
+                                       dataSource = null;
+                               }
+                               base.Dispose (disposing);
+                               disposed = true;
+                       }
                }
 
-                object ICloneable.Clone()
-                {
-                        throw new NotImplementedException ();
-                }
+               [MonoTODO]
+               public void EnlistDistributedTransaction (ITransaction transaction)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               object ICloneable.Clone ()
+               {
+                       return new TdsConnection (ConnectionString);
+               }
 
                IDbTransaction IDbConnection.BeginTransaction ()
                {
                        return BeginTransaction ();
                }
 
-               IDbTransaction IDbConnection.BeginTransaction (IsolationLevel il)
+               IDbTransaction IDbConnection.BeginTransaction (IsolationLevel iso)
                {
-                       return BeginTransaction (il);
+                       return BeginTransaction (iso);
                }
 
                IDbCommand IDbConnection.CreateCommand ()
@@ -265,45 +273,32 @@ namespace Mono.Data.TdsClient {
                        return CreateCommand ();
                }
 
-               static bool IsValidDatabaseName (string database)
+               void IDisposable.Dispose ()
                {
-                       if (database.Length > 32 || database.Length < 1)
-                               return false;
-
-                       if (database[0] == '"' && database[database.Length] == '"')
-                               database = database.Substring (1, database.Length - 2);
-                       else if (Char.IsDigit (database[0]))
-                               return false;
-
-                       if (database[0] == '_')
-                               return false;
-
-                       foreach (char c in database.Substring (1, database.Length - 1))
-                               if (!Char.IsLetterOrDigit (c) && c != '_')
-                                       return false;
-                       return true;
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
                }
 
-               public void Open ()
+               [MonoTODO ("Figure out the Tds way to reset the connection.")]
+               public void Open () 
                {
                        if (connectionString == null)
-                               throw new InvalidOperationException ("The ConnectionString property has not been initialized.");
-                       if (parms.User == null)
-                               throw new ArgumentException ("User name is null.");
-                       if (parms.Password == null)
-                               throw new ArgumentException ("Password is null.  This may be a bug with blank passwords.");
-
-                       if (!pooling)
-                               tds = new Tds42 (DataSource, port, PacketSize, ConnectionTimeout);
-                       else {
-                               pool = (TdsConnectionPool) pools[connectionString];
-                               if (pool == null) {
-                                       lock (pools) {
+                               throw new InvalidOperationException ("Connection string has not been initialized.");
+
+                       try {
+                               if (!pooling)
+                                       tds = new Tds42 (DataSource, port, PacketSize, ConnectionTimeout);
+                               else {
+                                       pool = (TdsConnectionPool) TdsConnectionPools [connectionString];
+                                       if (pool == null) {
                                                pool = new TdsConnectionPool (dataSource, port, packetSize, ConnectionTimeout, minPoolSize, maxPoolSize);
-                                               pools[connectionString] = pool;
+                                               TdsConnectionPools [connectionString] = pool;
                                        }
+                                       tds = pool.AllocateConnection ();
                                }
-                               tds = pool.AllocateConnection ();
+                       }
+                       catch (TdsTimeoutException e) {
+                               throw TdsException.FromTdsInternalException ((TdsInternalException) e);
                        }
 
                        tds.TdsErrorMessage += new TdsInternalErrorMessageEventHandler (ErrorHandler);
@@ -311,190 +306,211 @@ namespace Mono.Data.TdsClient {
 
                        if (!tds.IsConnected) {
                                tds.Connect (parms);
+                               ChangeState (ConnectionState.Open);
                                ChangeDatabase (parms.Database);
                        }
-
-                       ChangeState (ConnectionState.Open);
-               }
-
-               [MonoTODO]
-               private void SetConnectionString (string connectionString)
-               {
-                       connectionString += ";";
-                       NameValueCollection parameters = new NameValueCollection ();
-
-                       if (connectionString == String.Empty)
-                               return;
-
-                       bool inQuote = false;
-                       bool inDQuote = false;
-
-                       string name = String.Empty;
-                       string value = String.Empty;
-                       StringBuilder sb = new StringBuilder ();
-
-                       foreach (char c in connectionString)
-                       {
-                               switch (c) {
-                               case '\'':
-                                       inQuote = !inQuote;
-                                       break;
-                               case '"' :
-                                       inDQuote = !inDQuote;
-                                       break;
-                               case ';' :
-                                       if (!inDQuote && !inQuote) {
-                                               value = sb.ToString ();
-                                               parameters [name.ToUpper ().Trim ()] = value.Trim ();
-                                               name = String.Empty;
-                                               value = String.Empty;
-                                               sb = new StringBuilder ();
-                                       }
-                                       else
-                                               sb.Append (c);
-                                       break;
-                               case '=' :
-                                       if (!inDQuote && !inQuote) {
-                                               name = sb.ToString ();
-                                               sb = new StringBuilder ();
-                                       }
-                                       else
-                                               sb.Append (c);
-                                       break;
-                               default:
-                                       sb.Append (c);
-                                       break;
-                               }
+                       else if (connectionReset) {
+                               // tds.ExecuteNonQuery ("EXEC sp_reset_connection"); FIXME
+                               ChangeState (ConnectionState.Open);
                        }
+               }
 
-                       if (this.ConnectionString == null)
-                       {
-                               SetDefaultConnectionParameters (parameters);
-                       }
+                void SetConnectionString (string connectionString)
+                {
+                        connectionString += ";";
+                        NameValueCollection parameters = new NameValueCollection ();
+
+                        if (connectionString == String.Empty)
+                                return;
+
+                        bool inQuote = false;
+                        bool inDQuote = false;
+
+                        string name = String.Empty;
+                        string value = String.Empty;
+                        StringBuilder sb = new StringBuilder ();
+
+                        foreach (char c in connectionString)
+                        {
+                                switch (c) {
+                                case '\'':
+                                        inQuote = !inQuote;
+                                        break;
+                                case '"' :
+                                        inDQuote = !inDQuote;
+                                        break;
+                                case ';' :
+                                        if (!inDQuote && !inQuote) {
+                                               if (name != String.Empty && name != null) {
+                                                       value = sb.ToString ();
+                                                       parameters [name.ToUpper ().Trim ()] = value.Trim ();
+                                               }
+                                                name = String.Empty;
+                                                value = String.Empty;
+                                                sb = new StringBuilder ();
+                                        }
+                                        else
+                                                sb.Append (c);
+                                        break;
+                                case '=' :
+                                        if (!inDQuote && !inQuote) {
+                                                name = sb.ToString ();
+                                                sb = new StringBuilder ();
+                                        }
+                                        else
+                                                sb.Append (c);
+                                        break;
+                                default:
+                                        sb.Append (c);
+                                        break;
+                                }
+                        }
+
+                        if (this.ConnectionString == null)
+                        {
+                                SetDefaultConnectionParameters (parameters);
+                        }
+
+                        SetProperties (parameters);
+
+                        this.connectionString = connectionString;
+                }
 
-                       SetProperties (parameters);
+                void SetDefaultConnectionParameters (NameValueCollection parameters)
+                {
+                        if (null == parameters.Get ("APPLICATION NAME"))
+                                parameters["APPLICATION NAME"] = ".Net TdsClient Data Provider";
+                        if (null == parameters.Get ("CONNECT TIMEOUT") && null == parameters.Get ("CONNECTION TIMEOUT"))
+                                parameters["CONNECT TIMEOUT"] = "15";
+                        if (null == parameters.Get ("CONNECTION LIFETIME"))
+                                parameters["CONNECTION LIFETIME"] = "0";
+                        if (null == parameters.Get ("CONNECTION RESET"))
+                                parameters["CONNECTION RESET"] = "true";
+                        if (null == parameters.Get ("ENLIST"))
+                                parameters["ENLIST"] = "true";
+                        if (null == parameters.Get ("INTEGRATED SECURITY") && null == parameters.Get ("TRUSTED_CONNECTION"))
+                                parameters["INTEGRATED SECURITY"] = "false";
+                        if (null == parameters.Get ("MAX POOL SIZE"))
+                                parameters["MAX POOL SIZE"] = "100";
+                        if (null == parameters.Get ("MIN POOL SIZE"))
+                                parameters["MIN POOL SIZE"] = "0";
+                        if (null == parameters.Get ("NETWORK LIBRARY") && null == parameters.Get ("NET"))
+                                parameters["NETWORK LIBRARY"] = "dbmssocn";
+                        if (null == parameters.Get ("PACKET SIZE"))
+                                parameters["PACKET SIZE"] = "512";
+                        if (null == parameters.Get ("PERSIST SECURITY INFO"))
+                                parameters["PERSIST SECURITY INFO"] = "false";
+                        if (null == parameters.Get ("POOLING"))
+                                parameters["POOLING"] = "true";
+                        if (null == parameters.Get ("WORKSTATION ID"))
+                                parameters["WORKSTATION ID"] = Dns.GetHostByName ("localhost").HostName;
+                }
 
-                       this.connectionString = connectionString;
+                private void SetProperties (NameValueCollection parameters)
+                {
+                        string value;
+                        foreach (string name in parameters) {
+                                value = parameters[name];
+
+                                switch (name) {
+                                case "APPLICATION NAME" :
+                                        parms.ApplicationName = value;
+                                        break;
+                                case "ATTACHDBFILENAME" :
+                                case "EXTENDED PROPERTIES" :
+                                case "INITIAL FILE NAME" :
+                                        break;
+                                case "CONNECT TIMEOUT" :
+                                case "CONNECTION TIMEOUT" :
+                                        connectionTimeout = Int32.Parse (value);
+                                        break;
+                                case "CONNECTION LIFETIME" :
+                                        break;
+                                case "CONNECTION RESET" :
+                                        connectionReset = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
+                                        break;
+                                case "CURRENT LANGUAGE" :
+                                        parms.Language = value;
+                                        break;
+                                case "DATA SOURCE" :
+                                case "SERVER" :
+                                case "ADDRESS" :
+                                case "ADDR" :
+                                case "NETWORK ADDRESS" :
+                                        dataSource = value;
+                                        break;
+                                case "ENLIST" :
+                                        break;
+                                case "INITIAL CATALOG" :
+                                case "DATABASE" :
+                                        parms.Database = value;
+                                        break;
+                                case "INTEGRATED SECURITY" :
+                                case "TRUSTED_CONNECTION" :
+                                        break;
+                                case "MAX POOL SIZE" :
+                                        maxPoolSize = Int32.Parse (value);
+                                        break;
+                                case "MIN POOL SIZE" :
+                                        minPoolSize = Int32.Parse (value);
+                                        break;
+                                case "NET" :
+                                case "NETWORK LIBRARY" :
+                                        if (!value.ToUpper ().Equals ("DBMSSOCN"))
+                                                throw new ArgumentException ("Unsupported network library.");
+                                        break;
+                                case "PACKET SIZE" :
+                                        packetSize = Int32.Parse (value);
+                                        break;
+                                case "PASSWORD" :
+                                case "PWD" :
+                                        parms.Password = value;
+                                        break;
+                                case "PERSIST SECURITY INFO" :
+                                        break;
+                                case "POOLING" :
+                                        pooling = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
+                                        break;
+                                case "USER ID" :
+                                        parms.User = value;
+                                        break;
+                                case "WORKSTATION ID" :
+                                        parms.Hostname = value;
+                                        break;
+                                }
+                       }
                }
 
 
-               private void SetDefaultConnectionParameters (NameValueCollection parameters)
-               {
-                       if (null == parameters.Get ("APPLICATION NAME"))
-                               parameters["APPLICATION NAME"] = ".Net SqlClient Data Provider";
-                       if (null == parameters.Get ("CONNECT TIMEOUT") && null == parameters.Get ("CONNECTION TIMEOUT"))
-                               parameters["CONNECT TIMEOUT"] = "15";
-                       if (null == parameters.Get ("CONNECTION LIFETIME"))
-                               parameters["CONNECTION LIFETIME"] = "0";
-                       if (null == parameters.Get ("CONNECTION RESET"))
-                               parameters["CONNECTION RESET"] = "true";
-                       if (null == parameters.Get ("ENLIST"))
-                               parameters["ENLIST"] = "true";
-                       if (null == parameters.Get ("INTEGRATED SECURITY") && null == parameters.Get ("TRUSTED_CONNECTION"))
-                               parameters["INTEGRATED SECURITY"] = "false";
-                       if (null == parameters.Get ("MAX POOL SIZE"))
-                               parameters["MAX POOL SIZE"] = "100";
-                       if (null == parameters.Get ("MIN POOL SIZE"))
-                               parameters["MIN POOL SIZE"] = "0";
-                       if (null == parameters.Get ("NETWORK LIBRARY") && null == parameters.Get ("NET"))
-                               parameters["NETWORK LIBRARY"] = "dbmssocn";
-                       if (null == parameters.Get ("PACKET SIZE"))
-                               parameters["PACKET SIZE"] = "512";
-                       if (null == parameters.Get ("PERSIST SECURITY INFO"))
-                               parameters["PERSIST SECURITY INFO"] = "false";
-                       if (null == parameters.Get ("POOLING"))
-                               parameters["POOLING"] = "true";
-                       if (null == parameters.Get ("WORKSTATION ID"))
-                               parameters["WORKSTATION ID"] = Dns.GetHostByName ("localhost").HostName;
-               }
-
-               private void SetProperties (NameValueCollection parameters)
+               static bool IsValidDatabaseName (string database)
                {
-                       string value;
-                       foreach (string name in parameters) {
-                               value = parameters[name];
-
-                               switch (name) {
-                               case "APPLICATION NAME" :
-                                       parms.ApplicationName = value;
-                                       break;
-                               case "ATTACHDBFILENAME" :
-                               case "EXTENDED PROPERTIES" :
-                               case "INITIAL FILE NAME" :
-                                       break;
-                               case "CONNECT TIMEOUT" :
-                               case "CONNECTION TIMEOUT" :
-                                       connectionTimeout = Int32.Parse (value);
-                                       break;
-                               case "CONNECTION LIFETIME" :
-                                       break;
-                               case "CONNECTION RESET" :
-                                       connectionReset = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
-                                       break;
-                               case "CURRENT LANGUAGE" :
-                                       parms.Language = value;
-                                       break;
-                               case "DATA SOURCE" :
-                               case "SERVER" :
-                               case "ADDRESS" :
-                               case "ADDR" :
-                               case "NETWORK ADDRESS" :
-                                       dataSource = value;
-                                       break;
-                               case "ENLIST" :
-                                       break;
-                               case "INITIAL CATALOG" :
-                               case "DATABASE" :
-                                       parms.Database = value;
-                                       break;
-                               case "INTEGRATED SECURITY" :
-                               case "TRUSTED_CONNECTION" :
-                                       break;
-                               case "MAX POOL SIZE" :
-                                       maxPoolSize = Int32.Parse (value);
-                                       break;
-                               case "MIN POOL SIZE" :
-                                       minPoolSize = Int32.Parse (value);
-                                       break;
-                               case "NET" :
-                               case "NETWORK LIBRARY" :
-                                       if (!value.ToUpper ().Equals ("DBMSSOCN"))
-                                               throw new NotSupportedException ("Unsupported network library.");
-                                       break;
-                               case "PACKET SIZE" :
-                                       packetSize = Int32.Parse (value);
-                                       break;
-                               case "PASSWORD" :
-                               case "PWD" :
-                                       parms.Password = value;
-                                       break;
-                               case "PERSIST SECURITY INFO" :
-                                       break;
-                               case "POOLING" :
-                                       pooling = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
-                                       break;
-                               case "USER ID" :
-                                       parms.User = value;
-                                       break;
-                               case "WORKSTATION ID" :
-                                       parms.Hostname = value;
-                                       break;
-                               }
-                       }
+                       if (database.Length > 32 || database.Length < 1)
+                               return false;
+
+                       if (database[0] == '"' && database[database.Length] == '"')
+                               database = database.Substring (1, database.Length - 2);
+                       else if (Char.IsDigit (database[0]))
+                               return false;
+
+                       if (database[0] == '_')
+                               return false;
+
+                       foreach (char c in database.Substring (1, database.Length - 1))
+                               if (!Char.IsLetterOrDigit (c) && c != '_')
+                                       return false;
+                       return true;
                }
 
                private void OnTdsInfoMessage (TdsInfoMessageEventArgs value)
                {
-                       TdsInfoMessageEventHandler handler = (TdsInfoMessageEventHandler) Events [EventTdsInfoMessage];
-                       if (handler != null)
-                               handler (this, value);
+                       if (InfoMessage != null)
+                               InfoMessage (this, value);
                }
 
                private void OnStateChange (StateChangeEventArgs value)
                {
-                       StateChangeEventHandler handler = (StateChangeEventHandler) Events [EventStateChange];
-                       if (handler != null)
-                               handler (this, value);
+                       if (StateChange != null)
+                               StateChange (this, value);
                }
 
                #endregion // Methods
index c05a8c59e9630e4ebcc0765c09337520ea46b8af..c16e17d5d6d4672dde418534477166fafb0a902f 100644 (file)
@@ -2,11 +2,16 @@
 // Mono.Data.TdsClient.TdsDataReader.cs
 //
 // Author:
+//   Rodrigo Moya (rodrigo@ximian.com)
+//   Daniel Morgan (danmorg@sc.rr.com)
 //   Tim Coleman (tim@timcoleman.com)
 //
-// Copyright (C) 2002 Tim Coleman
+// (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
+// Copyright (C) Tim Coleman, 2002
 //
 
+using Mono.Data.TdsTypes;
 using Mono.Data.Tds.Protocol;
 using System;
 using System.Collections;
@@ -15,22 +20,20 @@ using System.Data;
 using System.Data.Common;
 
 namespace Mono.Data.TdsClient {
-        public class TdsDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
+       public sealed class TdsDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
        {
                #region Fields
 
+               TdsCommand command;
+               ArrayList dataTypeNames;
+               bool disposed = false;
                int fieldCount;
-               bool hasRows;
                bool isClosed;
-               int recordsAffected;
+               bool isSelect;
                bool moreResults;
-
-               ArrayList dataTypeNames;
-               ArrayList dataTypes;
-
-               TdsCommand command;
-
-               DataTable schemaTable = ConstructSchemaTable ();
+               int resultsRead;
+               int rowsRead;
+               DataTable schemaTable;
 
                #endregion // Fields
 
@@ -39,8 +42,12 @@ namespace Mono.Data.TdsClient {
                internal TdsDataReader (TdsCommand command)
                {
                        this.command = command;
-                       this.fieldCount = 0;
-                       this.isClosed = false;
+                       schemaTable = ConstructSchemaTable ();
+                       resultsRead = 0;
+                       fieldCount = 0;
+                       isClosed = false;
+                       isSelect = (command.CommandText.Trim ().ToUpper ().StartsWith ("SELECT"));
+                       command.Tds.RecordsAffected = 0;
                        NextResult ();
                }
 
@@ -56,10 +63,6 @@ namespace Mono.Data.TdsClient {
                        get { return fieldCount; }
                }
 
-               public bool HasRows {
-                       get { return hasRows; }
-               }
-
                public bool IsClosed {
                        get { return isClosed; }
                }
@@ -73,19 +76,22 @@ namespace Mono.Data.TdsClient {
                }
        
                public int RecordsAffected {
-                       get { return recordsAffected; }
+                       get { 
+                               if (isSelect) 
+                                       return -1;
+                               else
+                                       return command.Tds.RecordsAffected; 
+                       }
                }
 
                #endregion // Properties
 
-                #region Methods
+               #region Methods
 
-               [MonoTODO]
                public void Close ()
                {
                        isClosed = true;
-
-                       throw new NotImplementedException (); 
+                       command.CloseDataReader (moreResults);
                }
 
                private static DataTable ConstructSchemaTable ()
@@ -94,13 +100,14 @@ namespace Mono.Data.TdsClient {
                        Type stringType = Type.GetType ("System.String");
                        Type intType = Type.GetType ("System.Int32");
                        Type typeType = Type.GetType ("System.Type");
+                       Type shortType = Type.GetType ("System.Int16");
 
                        DataTable schemaTable = new DataTable ("SchemaTable");
                        schemaTable.Columns.Add ("ColumnName", stringType);
                        schemaTable.Columns.Add ("ColumnOrdinal", intType);
                        schemaTable.Columns.Add ("ColumnSize", intType);
-                       schemaTable.Columns.Add ("NumericPrecision", intType);
-                       schemaTable.Columns.Add ("NumericScale", intType);
+                       schemaTable.Columns.Add ("NumericPrecision", shortType);
+                       schemaTable.Columns.Add ("NumericScale", shortType);
                        schemaTable.Columns.Add ("IsUnique", booleanType);
                        schemaTable.Columns.Add ("IsKey", booleanType);
                        schemaTable.Columns.Add ("BaseServerName", stringType);
@@ -110,7 +117,7 @@ namespace Mono.Data.TdsClient {
                        schemaTable.Columns.Add ("BaseTableName", stringType);
                        schemaTable.Columns.Add ("DataType", typeType);
                        schemaTable.Columns.Add ("AllowDBNull", booleanType);
-                       schemaTable.Columns.Add ("ProviderType", booleanType);
+                       schemaTable.Columns.Add ("ProviderType", intType);
                        schemaTable.Columns.Add ("IsAliased", booleanType);
                        schemaTable.Columns.Add ("IsExpression", booleanType);
                        schemaTable.Columns.Add ("IsIdentity", booleanType);
@@ -123,46 +130,68 @@ namespace Mono.Data.TdsClient {
                        return schemaTable;
                }
 
-               [MonoTODO]
+               private void Dispose (bool disposing) 
+               {
+                       if (!disposed) {
+                               if (disposing) {
+                                       schemaTable.Dispose ();
+                                       Close ();
+                               }
+                               disposed = true;
+                       }
+               }
+
                public bool GetBoolean (int i)
                {
-                       throw new NotImplementedException (); 
+                       object value = GetValue (i);
+                       if (!(value is bool))
+                               throw new InvalidCastException ();
+                       return (bool) value;
                }
 
-               [MonoTODO]
                public byte GetByte (int i)
                {
-                       throw new NotImplementedException (); 
+                       object value = GetValue (i);
+                       if (!(value is byte))
+                               throw new InvalidCastException ();
+                       return (byte) value;
                }
 
-               [MonoTODO]
                public long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
                {
-                       throw new NotImplementedException (); 
+                       object value = GetValue (i);
+                       if (!(value is byte []))
+                               throw new InvalidCastException ();
+                       Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
+                       return ((byte []) value).Length - dataIndex;
                }
 
-               [MonoTODO]
                public char GetChar (int i)
                {
-                       throw new NotImplementedException (); 
+                       object value = GetValue (i);
+                       if (!(value is char))
+                               throw new InvalidCastException ();
+                       return (char) value;
                }
 
-               [MonoTODO]
                public long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
                {
-                       throw new NotImplementedException (); 
+                       object value = GetValue (i);
+                       if (!(value is char[]))
+                               throw new InvalidCastException ();
+                       Array.Copy ((char []) value, (int) dataIndex, buffer, bufferIndex, length);
+                       return ((char []) value).Length - dataIndex;
                }
 
-               [MonoTODO]
+               [MonoTODO ("Implement GetData")]
                public IDataReader GetData (int i)
                {
-                       throw new NotImplementedException (); 
+                       throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                public string GetDataTypeName (int i)
                {
-                       throw new NotImplementedException (); 
+                       return (string) dataTypeNames [i];
                }
 
                public DateTime GetDateTime (int i)
@@ -191,7 +220,7 @@ namespace Mono.Data.TdsClient {
 
                public Type GetFieldType (int i)
                {
-                       return GetValue (i).GetType ();
+                       return (Type) schemaTable.Rows[i]["DataType"];
                }
 
                public float GetFloat (int i)
@@ -202,10 +231,12 @@ namespace Mono.Data.TdsClient {
                        return (float) value;
                }
 
-               [MonoTODO]
                public Guid GetGuid (int i)
                {
-                       throw new NotImplementedException (); 
+                       object value = GetValue (i);
+                       if (!(value is Guid))
+                               throw new InvalidCastException ();
+                       return (Guid) value;
                }
 
                public short GetInt16 (int i)
@@ -237,13 +268,12 @@ namespace Mono.Data.TdsClient {
                        return (string) schemaTable.Rows[i]["ColumnName"];
                }
 
-               [MonoTODO]
                public int GetOrdinal (string name)
                {
-                       foreach (DataRow schemaRow in schemaTable.Rows) 
+                       foreach (DataRow schemaRow in schemaTable.Rows)
                                if (((string) schemaRow ["ColumnName"]).Equals (name))
                                        return (int) schemaRow ["ColumnOrdinal"];
-                       foreach (DataRow schemaRow in schemaTable.Rows) 
+                       foreach (DataRow schemaRow in schemaTable.Rows)
                                if (String.Compare (((string) schemaRow ["ColumnName"]), name, true) == 0)
                                        return (int) schemaRow ["ColumnOrdinal"];
                        throw new IndexOutOfRangeException ();
@@ -260,13 +290,12 @@ namespace Mono.Data.TdsClient {
                        fieldCount = 0;
 
                        dataTypeNames = new ArrayList ();
-                       dataTypes = new ArrayList ();
 
                        foreach (TdsSchemaInfo schema in command.Tds.Schema) {
                                DataRow row = schemaTable.NewRow ();
 
                                row ["ColumnName"]              = GetSchemaValue (schema, "ColumnName");
-                               row ["ColumnSize"]              = GetSchemaValue (schema, "ColumnSize");
+                               row ["ColumnSize"]              = GetSchemaValue (schema, "ColumnSize"); 
                                row ["ColumnOrdinal"]           = GetSchemaValue (schema, "ColumnOrdinal");
                                row ["NumericPrecision"]        = GetSchemaValue (schema, "NumericPrecision");
                                row ["NumericScale"]            = GetSchemaValue (schema, "NumericScale");
@@ -286,145 +315,148 @@ namespace Mono.Data.TdsClient {
                                row ["IsHidden"]                = GetSchemaValue (schema, "IsHidden");
                                row ["IsReadOnly"]              = GetSchemaValue (schema, "IsReadOnly");
 
+                               // We don't always get the base column name.
+                               if (row ["BaseColumnName"] == DBNull.Value)
+                                       row ["BaseColumnName"] = row ["ColumnName"];
+
                                switch ((TdsColumnType) schema ["ColumnType"]) {
-                               case TdsColumnType.Image :
-                                       dataTypeNames.Add ("image");
-                                       row ["ProviderType"] = (int) TdsType.Image;
-                                       row ["DataType"] = typeof (byte[]);
-                                       row ["IsLong"] = true;
-                                       break;
-                               case TdsColumnType.Text :
-                                       dataTypes.Add (typeof (string));
-                                       dataTypeNames.Add ("text");
-                                       row ["ProviderType"] = (int) TdsType.Text;
-                                       row ["DataType"] = typeof (string);
-                                       row ["IsLong"] = true;
-                                       break;
-                               case TdsColumnType.UniqueIdentifier :
-                                       dataTypeNames.Add ("uniqueidentifier");
-                                       row ["ProviderType"] = (int) TdsType.UniqueIdentifier;
-                                       row ["DataType"] = typeof (Guid);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.VarBinary :
-                               case TdsColumnType.BigVarBinary :
-                                       dataTypeNames.Add ("varbinary");
-                                       row ["ProviderType"] = (int) TdsType.VarBinary;
-                                       row ["DataType"] = typeof (byte[]);
-                                       row ["IsLong"] = true;
-                                       break;
-                               case TdsColumnType.IntN :
-                               case TdsColumnType.Int4 :
-                                       dataTypeNames.Add ("int");
-                                       row ["ProviderType"] = (int) TdsType.Int;
-                                       row ["DataType"] = typeof (int);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.VarChar :
-                               case TdsColumnType.BigVarChar :
-                                       dataTypeNames.Add ("varchar");
-                                       row ["ProviderType"] = (int) TdsType.VarChar;
-                                       row ["DataType"] = typeof (string);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.Binary :
-                               case TdsColumnType.BigBinary :
-                                       dataTypeNames.Add ("binary");
-                                       row ["ProviderType"] = (int) TdsType.Binary;
-                                       row ["DataType"] = typeof (byte[]);
-                                       row ["IsLong"] = true;
-                                       break;
-                               case TdsColumnType.Char :
-                               case TdsColumnType.BigChar :
-                                       dataTypeNames.Add ("char");
-                                       row ["ProviderType"] = (int) TdsType.Char;
-                                       row ["DataType"] = typeof (string);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.Int1 :
-                                       dataTypeNames.Add ("tinyint");
-                                       row ["ProviderType"] = (int) TdsType.TinyInt;
-                                       row ["DataType"] = typeof (byte);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.Bit :
-                               case TdsColumnType.BitN :
-                                       dataTypeNames.Add ("bit");
-                                       row ["ProviderType"] = (int) TdsType.Bit;
-                                       row ["DataType"] = typeof (bool);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.Int2 :
-                                       dataTypeNames.Add ("smallint");
-                                       row ["ProviderType"] = (int) TdsType.SmallInt;
-                                       row ["DataType"] = typeof (short);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.DateTime4 :
-                               case TdsColumnType.DateTime :
-                               case TdsColumnType.DateTimeN :
-                                       dataTypeNames.Add ("datetime");
-                                       row ["ProviderType"] = (int) TdsType.DateTime;
-                                       row ["DataType"] = typeof (DateTime);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.Real :
-                                       dataTypeNames.Add ("real");
-                                       row ["ProviderType"] = (int) TdsType.Real;
-                                       row ["DataType"] = typeof (float);
-                                       break;
-                               case TdsColumnType.Money :
-                               case TdsColumnType.MoneyN :
-                               case TdsColumnType.Money4 :
-                                       dataTypeNames.Add ("money");
-                                       row ["ProviderType"] = (int) TdsType.Money;
-                                       row ["DataType"] = typeof (decimal);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.Float8 :
-                               case TdsColumnType.FloatN :
-                                       dataTypeNames.Add ("float");
-                                       row ["ProviderType"] = (int) TdsType.Float;
-                                       row ["DataType"] = typeof (double);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.NText :
-                                       dataTypeNames.Add ("ntext");
-                                       row ["ProviderType"] = (int) TdsType.NText;
-                                       row ["DataType"] = typeof (string);
-                                       row ["IsLong"] = true;
-                                       break;
-                               case TdsColumnType.NVarChar :
-                                       dataTypeNames.Add ("nvarchar");
-                                       row ["ProviderType"] = (int) TdsType.NVarChar;
-                                       row ["DataType"] = typeof (string);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.Decimal :
-                               case TdsColumnType.Numeric :
-                                       dataTypeNames.Add ("decimal");
-                                       row ["ProviderType"] = (int) TdsType.Decimal;
-                                       row ["DataType"] = typeof (decimal);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.NChar :
-                                       dataTypeNames.Add ("nchar");
-                                       row ["ProviderType"] = (int) TdsType.Char;
-                                       row ["DataType"] = typeof (string);
-                                       row ["IsLong"] = false;
-                                       break;
-                               case TdsColumnType.SmallMoney :
-                                       dataTypeNames.Add ("smallmoney");
-                                       row ["ProviderType"] = (int) TdsType.SmallMoney;
-                                       row ["DataType"] = typeof (decimal);
-                                       row ["IsLong"] = false;
-                                       break;
-                               default :
-                                       dataTypeNames.Add ("variant");
-                                       row ["ProviderType"] = (int) TdsType.Variant;
-                                       row ["DataType"] = typeof (object);
-                                       row ["IsLong"] = false;
-                                       break;
+                                       case TdsColumnType.Image :
+                                               dataTypeNames.Add ("image");
+                                               row ["ProviderType"] = (int) TdsType.Image;
+                                               row ["DataType"] = typeof (byte[]);
+                                               row ["IsLong"] = true;
+                                               break;
+                                       case TdsColumnType.Text :
+                                               dataTypeNames.Add ("text");
+                                               row ["ProviderType"] = (int) TdsType.Text;
+                                               row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = true;
+                                               break;
+                                       case TdsColumnType.UniqueIdentifier :
+                                               dataTypeNames.Add ("uniqueidentifier");
+                                               row ["ProviderType"] = (int) TdsType.UniqueIdentifier;
+                                               row ["DataType"] = typeof (Guid);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.VarBinary :
+                                       case TdsColumnType.BigVarBinary :
+                                               dataTypeNames.Add ("varbinary");
+                                               row ["ProviderType"] = (int) TdsType.VarBinary;
+                                               row ["DataType"] = typeof (byte[]);
+                                               row ["IsLong"] = true;
+                                               break;
+                                       case TdsColumnType.IntN :
+                                       case TdsColumnType.Int4 :
+                                               dataTypeNames.Add ("int");
+                                               row ["ProviderType"] = (int) TdsType.Int;
+                                               row ["DataType"] = typeof (int);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.VarChar :
+                                       case TdsColumnType.BigVarChar :
+                                               dataTypeNames.Add ("varchar");
+                                               row ["ProviderType"] = (int) TdsType.VarChar;
+                                               row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.Binary :
+                                       case TdsColumnType.BigBinary :
+                                               dataTypeNames.Add ("binary");
+                                               row ["ProviderType"] = (int) TdsType.Binary;
+                                               row ["DataType"] = typeof (byte[]);
+                                               row ["IsLong"] = true;
+                                               break;
+                                       case TdsColumnType.Char :
+                                       case TdsColumnType.BigChar :
+                                               dataTypeNames.Add ("char");
+                                               row ["ProviderType"] = (int) TdsType.Char;
+                                               row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.Int1 :
+                                               dataTypeNames.Add ("tinyint");
+                                               row ["ProviderType"] = (int) TdsType.TinyInt;
+                                               row ["DataType"] = typeof (byte);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.Bit :
+                                       case TdsColumnType.BitN :
+                                               dataTypeNames.Add ("bit");
+                                               row ["ProviderType"] = (int) TdsType.Bit;
+                                               row ["DataType"] = typeof (bool);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.Int2 :
+                                               dataTypeNames.Add ("smallint");
+                                               row ["ProviderType"] = (int) TdsType.SmallInt;
+                                               row ["DataType"] = typeof (short);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.DateTime4 :
+                                       case TdsColumnType.DateTime :
+                                       case TdsColumnType.DateTimeN :
+                                               dataTypeNames.Add ("datetime");
+                                               row ["ProviderType"] = (int) TdsType.DateTime;
+                                               row ["DataType"] = typeof (DateTime);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.Real :
+                                               dataTypeNames.Add ("real");
+                                               row ["ProviderType"] = (int) TdsType.Real;
+                                               row ["DataType"] = typeof (float);
+                                               break;
+                                       case TdsColumnType.Money :
+                                       case TdsColumnType.MoneyN :
+                                       case TdsColumnType.Money4 :
+                                               dataTypeNames.Add ("money");
+                                               row ["ProviderType"] = (int) TdsType.Money;
+                                               row ["DataType"] = typeof (decimal);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.Float8 :
+                                       case TdsColumnType.FloatN :
+                                               dataTypeNames.Add ("float");
+                                               row ["ProviderType"] = (int) TdsType.Float;
+                                               row ["DataType"] = typeof (double);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.NText :
+                                               dataTypeNames.Add ("ntext");
+                                               row ["ProviderType"] = (int) TdsType.NText;
+                                               row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = true;
+                                               break;
+                                       case TdsColumnType.NVarChar :
+                                               dataTypeNames.Add ("nvarchar");
+                                               row ["ProviderType"] = (int) TdsType.NVarChar;
+                                               row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.Decimal :
+                                       case TdsColumnType.Numeric :
+                                               dataTypeNames.Add ("decimal");
+                                               row ["ProviderType"] = (int) TdsType.Decimal;
+                                               row ["DataType"] = typeof (decimal);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.NChar :
+                                               dataTypeNames.Add ("nchar");
+                                               row ["ProviderType"] = (int) TdsType.NChar;
+                                               row ["DataType"] = typeof (string);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       case TdsColumnType.SmallMoney :
+                                               dataTypeNames.Add ("smallmoney");
+                                               row ["ProviderType"] = (int) TdsType.SmallMoney;
+                                               row ["DataType"] = typeof (decimal);
+                                               row ["IsLong"] = false;
+                                               break;
+                                       default :
+                                               dataTypeNames.Add ("variant");
+                                               row ["ProviderType"] = (int) TdsType.Variant;
+                                               row ["DataType"] = typeof (object);
+                                               row ["IsLong"] = false;
+                                               break;
                                }
 
                                schemaTable.Rows.Add (row);
@@ -432,7 +464,7 @@ namespace Mono.Data.TdsClient {
                                fieldCount += 1;
                        }
                        return schemaTable;
-               }
+               }               
 
                private static object GetSchemaValue (TdsSchemaInfo schema, object key)
                {
@@ -441,6 +473,200 @@ namespace Mono.Data.TdsClient {
                        return DBNull.Value;
                }
 
+               public TdsBinary GetTdsBinary (int i)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public TdsBoolean GetTdsBoolean (int i) 
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsBoolean))
+                               throw new InvalidCastException ();
+                       return (TdsBoolean) value;
+               }
+
+               public TdsByte GetTdsByte (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsByte))
+                               throw new InvalidCastException ();
+                       return (TdsByte) value;
+               }
+
+               public TdsDateTime GetTdsDateTime (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsDateTime))
+                               throw new InvalidCastException ();
+                       return (TdsDateTime) value;
+               }
+
+               public TdsDecimal GetTdsDecimal (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsDecimal))
+                               throw new InvalidCastException ();
+                       return (TdsDecimal) value;
+               }
+
+               public TdsDouble GetTdsDouble (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsDouble))
+                               throw new InvalidCastException ();
+                       return (TdsDouble) value;
+               }
+
+               public TdsGuid GetTdsGuid (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsGuid))
+                               throw new InvalidCastException ();
+                       return (TdsGuid) value;
+               }
+
+               public TdsInt16 GetTdsInt16 (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsInt16))
+                               throw new InvalidCastException ();
+                       return (TdsInt16) value;
+               }
+
+               public TdsInt32 GetTdsInt32 (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsInt32))
+                               throw new InvalidCastException ();
+                       return (TdsInt32) value;
+               }
+
+               public TdsInt64 GetTdsInt64 (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsInt64))
+                               throw new InvalidCastException ();
+                       return (TdsInt64) value;
+               }
+
+               public TdsMoney GetTdsMoney (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsMoney))
+                               throw new InvalidCastException ();
+                       return (TdsMoney) value;
+               }
+
+               public TdsSingle GetTdsSingle (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsSingle))
+                               throw new InvalidCastException ();
+                       return (TdsSingle) value;
+               }
+
+               public TdsString GetTdsString (int i)
+               {
+                       object value = GetTdsValue (i);
+                       if (!(value is TdsString))
+                               throw new InvalidCastException ();
+                       return (TdsString) value;
+               }
+
+               [MonoTODO ("Implement TdsBigDecimal conversion.  TdsType.Real fails tests?")]
+               public object GetTdsValue (int i)
+               {
+                       TdsType type = (TdsType) (schemaTable.Rows [i]["ProviderType"]);
+                       object value = GetValue (i);
+
+                       switch (type) {
+                       case TdsType.BigInt:
+                               if (value == null)
+                                       return TdsInt64.Null;
+                               return (TdsInt64) ((long) value);
+                       case TdsType.Binary:
+                       case TdsType.Image:
+                       case TdsType.VarBinary:
+                       case TdsType.Timestamp:
+                               if (value == null)
+                                       return TdsBinary.Null;
+                               return (TdsBinary) ((byte[]) value);
+                       case TdsType.Bit:
+                               if (value == null)
+                                       return TdsBoolean.Null;
+                               return (TdsBoolean) ((bool) value);
+                       case TdsType.Char:
+                       case TdsType.NChar:
+                       case TdsType.NText:
+                       case TdsType.NVarChar:
+                       case TdsType.Text:
+                       case TdsType.VarChar:
+                               if (value == null)
+                                       return TdsString.Null;
+                               return (TdsString) ((string) value);
+                       case TdsType.DateTime:
+                       case TdsType.SmallDateTime:
+                               if (value == null)
+                                       return TdsDateTime.Null;
+                               return (TdsDateTime) ((DateTime) value);
+                       case TdsType.Decimal:
+                               if (value == null)
+                                       return TdsDecimal.Null;
+                               if (value is TdsBigDecimal)
+                                       return TdsDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
+                               return (TdsDecimal) ((decimal) value);
+                       case TdsType.Float:
+                               if (value == null)
+                                       return TdsDouble.Null;
+                               return (TdsDouble) ((double) value);
+                       case TdsType.Int:
+                               if (value == null)
+                                       return TdsInt32.Null;
+                               return (TdsInt32) ((int) value);
+                       case TdsType.Money:
+                       case TdsType.SmallMoney:
+                               if (value == null)
+                                       return TdsMoney.Null;
+                               return (TdsMoney) ((decimal) value);
+                       case TdsType.Real:
+                               if (value == null)
+                                       return TdsSingle.Null;
+                               return (TdsSingle) ((float) value);
+                       case TdsType.UniqueIdentifier:
+                               if (value == null)
+                                       return TdsGuid.Null;
+                               return (TdsGuid) ((Guid) value);
+                       case TdsType.SmallInt:
+                               if (value == null)
+                                       return TdsInt16.Null;
+                               return (TdsInt16) ((short) value);
+                       case TdsType.TinyInt:
+                               if (value == null)
+                                       return TdsByte.Null;
+                               return (TdsByte) ((byte) value);
+                       }
+
+                       throw new InvalidOperationException ("The type of this column is unknown.");
+               }
+
+               public int GetTdsValues (object[] values)
+               {
+                       int count = 0;
+                       int columnCount = schemaTable.Rows.Count;
+                       int arrayCount = values.Length;
+
+                       if (arrayCount > columnCount)
+                               count = columnCount;
+                       else
+                               count = arrayCount;
+
+                       for (int i = 0; i < count; i += 1) 
+                               values [i] = GetTdsValue (i);
+
+                       return count;
+               }
+
                public string GetString (int i)
                {
                        object value = GetValue (i);
@@ -451,45 +677,72 @@ namespace Mono.Data.TdsClient {
 
                public object GetValue (int i)
                {
-                       return command.Tds.ColumnValues[i];
+                       return command.Tds.ColumnValues [i];
                }
 
                public int GetValues (object[] values)
                {
                        int len = values.Length;
+                       int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
+
+                       // If a four-byte decimal is stored, then we can't convert to
+                       // a native type.  Throw an OverflowException.
+                       if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
+                               throw new OverflowException ();
+
                        command.Tds.ColumnValues.CopyTo (0, values, 0, len);
                        return (len > FieldCount ? len : FieldCount);
                }
 
-               [MonoTODO]
                void IDisposable.Dispose ()
                {
-                       throw new NotImplementedException (); 
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
                }
 
-               [MonoTODO]
                IEnumerator IEnumerable.GetEnumerator ()
                {
-                       throw new NotImplementedException (); 
+                       return new DbEnumerator (this);
                }
 
-               [MonoTODO]
                public bool IsDBNull (int i)
                {
-                       throw new NotImplementedException (); 
+                       return GetValue (i) == null;
                }
 
                public bool NextResult ()
                {
+                       if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0)
+                               return false;
+                       if (command.Tds.DoneProc)
+                               return false;
+
                        schemaTable.Rows.Clear ();
-                       return command.Tds.NextResult ();
+
+                       moreResults = command.Tds.NextResult ();
+                       GetSchemaTable ();
+
+                       rowsRead = 0;
+                       resultsRead += 1;
+                       return moreResults;
                }
 
                public bool Read ()
                {
-                       return command.Tds.NextRow ();
+                       if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && rowsRead > 0)
+                               return false;
+                       if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
+                               return false;
+                       if (!moreResults)
+                               return false;
+
+                       bool result = command.Tds.NextRow ();
+
+                       rowsRead += 1;
+
+                       return result;
                }
 
-                #endregion // Methods
+               #endregion // Methods
        }
 }
index 7e6222f2c0cb327b9e8359b3145bd5255a8c949e..e88b45c151e7494e0012e1cfca196d29cb6d6290 100644 (file)
@@ -4,40 +4,35 @@
 // Author:
 //   Tim Coleman (tim@timcoleman.com)
 //
-// Copyright (C) 2002 Tim Coleman
+// Copyright (C) Tim Coleman, 2002
 //
 
 using Mono.Data.Tds.Protocol;
 using System;
+using System.Data;
 using System.Runtime.Serialization;
+using System.Text;
 
 namespace Mono.Data.TdsClient {
-        public class TdsException : SystemException
+       [Serializable]
+       public sealed class TdsException : SystemException
        {
                #region Fields
 
-               byte theClass;
-               TdsErrorCollection errors;
-               int lineNumber;
-               string message;
-               int number;
-               string procedure;
-               string server;
-               string source;
-               byte state;
+               TdsErrorCollection errors; 
 
-               #endregion // Fields
+               #endregion Fields
 
                #region Constructors
 
-               internal TdsException ()
-                       : base ("a TDS Exception has occurred.")
+               internal TdsException () 
+                       : base ("a SQL Exception has occurred.") 
                {
                        errors = new TdsErrorCollection();
                }
 
-               internal TdsException (byte theClass, int lineNumber, string message, int number, string procedure, string server, string source, byte state)
-                       : base (message)
+               internal TdsException (byte theClass, int lineNumber, string message, int number, string procedure, string server, string source, byte state) 
+                       : base (message) 
                {
                        errors = new TdsErrorCollection (theClass, lineNumber, message, number, procedure, server, source, state);
                }
@@ -47,7 +42,7 @@ namespace Mono.Data.TdsClient {
                #region Properties
 
                public byte Class {
-                       get { return theClass; }
+                       get { return errors [0].Class; }
                }
 
                public TdsErrorCollection Errors {
@@ -55,31 +50,39 @@ namespace Mono.Data.TdsClient {
                }
 
                public int LineNumber {
-                       get { return lineNumber; }
+                       get { return errors [0].LineNumber; }
                }
-
-               public override string Message {
-                       get { return message; }
+               
+               public override string Message  {
+                       get {
+                               StringBuilder result = new StringBuilder ();
+                               foreach (TdsError error in Errors) {
+                                       if (result.Length > 0)
+                                               result.Append ('\n');
+                                       result.Append (error.Message);
+                               }
+                               return result.ToString ();
+                       }                                                                
                }
-
+               
                public int Number {
-                       get { return number; }
+                       get { return errors [0].Number; }
                }
-
+               
                public string Procedure {
-                       get { return procedure; }
+                       get { return errors [0].Procedure; }
                }
 
                public string Server {
-                       get { return server; }
+                       get { return errors [0].Server; }
                }
-
+               
                public override string Source {
-                       get { return source; }
+                       get { return errors [0].Source; }
                }
 
                public byte State {
-                       get { return state; }
+                       get { return errors [0].State; }
                }
 
                #endregion // Properties
@@ -87,11 +90,16 @@ namespace Mono.Data.TdsClient {
                #region Methods
 
                [MonoTODO]
-               public override void GetObjectData (SerializationInfo si, StreamingContext context)
+               public override void GetObjectData (SerializationInfo si, StreamingContext context) 
                {
                        throw new NotImplementedException ();
                }
 
+               internal static TdsException FromTdsInternalException (TdsInternalException e)
+               {
+                       return new TdsException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono TdsClient Data Provider", e.State);
+               }
+
                #endregion // Methods
        }
 }
index 454ab174bda4e3e9139ce18565dbcc312877ac28..7cc4280b2da743b8e29b8f413fae06edce3bd06d 100644 (file)
 // Mono.Data.TdsClient.TdsParameter.cs
 //
 // Author:
+//   Rodrigo Moya (rodrigo@ximian.com)
+//   Daniel Morgan (danmorg@sc.rr.com)
 //   Tim Coleman (tim@timcoleman.com)
 //
+// (C) Ximian, Inc. 2002
 // Copyright (C) Tim Coleman, 2002
 //
 
+using Mono.Data.Tds;
+using Mono.Data.Tds.Protocol;
 using System;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
 using System.Runtime.InteropServices;
+using System.Text;
 
 namespace Mono.Data.TdsClient {
-       public sealed class TdsParameter : IDbDataParameter, IDataParameter
+       public sealed class TdsParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
        {
                #region Fields
 
+               TdsMetaParameter metaParameter;
+
+               TdsParameterCollection container = null;
                DbType dbType;
-               ParameterDirection direction;
+               ParameterDirection direction = ParameterDirection.Input;
                bool isNullable;
+               bool isSizeSet = false;
+               bool isTypeSet = false;
                int offset;
-               string parameterName;
-               object objectValue;
+               TdsType sybaseType;
                string sourceColumn;
                DataRowVersion sourceVersion;
-               byte precision;
-               byte scale;
-               int size;
 
                #endregion // Fields
 
                #region Constructors
 
-               public TdsParameter ()
+               public TdsParameter () 
+                       : this (String.Empty, TdsType.NVarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
+               {
+               }
+
+               public TdsParameter (string parameterName, object value) 
+               {
+                       metaParameter = new TdsMetaParameter (parameterName, value);
+                       this.sourceVersion = DataRowVersion.Current;
+                       InferTdsType (value);
+               }
+               
+               public TdsParameter (string parameterName, TdsType dbType) 
+                       : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
+               {
+               }
+
+               public TdsParameter (string parameterName, TdsType dbType, int size) 
+                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
+               {
+               }
+               
+               public TdsParameter (string parameterName, TdsType dbType, int size, string sourceColumn) 
+                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, sourceColumn, DataRowVersion.Current, null)
+               {
+               }
+               
+               [EditorBrowsable (EditorBrowsableState.Advanced)]        
+               public TdsParameter (string parameterName, TdsType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value) 
                {
+                       metaParameter = new TdsMetaParameter (parameterName, size, isNullable, precision, scale, value);
+
+                       TdsType = dbType;
+                       Direction = direction;
+                       SourceColumn = sourceColumn;
+                       SourceVersion = sourceVersion;
                }
 
-               public TdsParameter (string parameterName, object value)
+               // This constructor is used internally to construct a
+               // TdsParameter.  The value array comes from sp_procedure_params_rowset.
+               // This is in TdsCommand.DeriveParameters.
+               internal TdsParameter (object[] dbValues)
                {
-                       this.parameterName = parameterName;
-                       this.objectValue = value;
+                       Precision = 0;
+                       Scale = 0;
+                       Direction = ParameterDirection.Input;
+
+                       ParameterName = (string) dbValues[3];
+
+                       switch ((short) dbValues[5]) {
+                       case 1:
+                               Direction = ParameterDirection.Input;
+                               break;
+                       case 2:
+                               Direction = ParameterDirection.Output;
+                               break;
+                       case 3:
+                               Direction = ParameterDirection.InputOutput;
+                               break;
+                       case 4:
+                               Direction = ParameterDirection.ReturnValue;
+                               break;
+                       }
+
+                       IsNullable = (bool) dbValues[8];
+
+                       if (dbValues[12] != null)
+                               Precision = (byte) ((short) dbValues[12]);
+                       if (dbValues[13] != null)
+                               Scale = (byte) ((short) dbValues[13]);
+
+                       SetDbTypeName ((string) dbValues[16]);
                }
 
                #endregion // Constructors
 
                #region Properties
 
+               // Used to ensure that only one collection can contain this
+               // parameter
+               internal TdsParameterCollection Container {
+                       get { return container; }
+                       set { container = value; }
+               }
+
                public DbType DbType {
                        get { return dbType; }
-                       set { dbType = value; }
+                       set { 
+                               SetDbType (value); 
+                               isTypeSet = true;
+                       }
                }
 
                public ParameterDirection Direction {
                        get { return direction; }
-                       set { direction = value; }
+                       set { 
+                               direction = value; 
+                               if (direction == ParameterDirection.Output)
+                                       MetaParameter.Direction = TdsParameterDirection.Output;
+                       }
+               }
+
+               internal TdsMetaParameter MetaParameter {
+                       get { return metaParameter; }
                }
 
-               public bool IsNullable {
-                       get { return isNullable; }
+               string IDataParameter.ParameterName {
+                       get { return metaParameter.ParameterName; }
+                       set { metaParameter.ParameterName = value; }
+               }
+
+               public bool IsNullable  {
+                       get { return metaParameter.IsNullable; }
+                       set { metaParameter.IsNullable = value; }
                }
 
                public int Offset {
                        get { return offset; }
                        set { offset = value; }
                }
-
+               
                public string ParameterName {
-                       get { return parameterName; }
-                       set { parameterName = value; }
+                       get { return metaParameter.ParameterName; }
+                       set { metaParameter.ParameterName = value; }
                }
 
                public byte Precision {
-                       get { return precision; }
-                       set { precision = value; }
+                       get { return metaParameter.Precision; }
+                       set { metaParameter.Precision = value; }
                }
 
-               public byte Scale {
-                       get { return scale; }
-                       set { scale = value; }
+                public byte Scale {
+                       get { return metaParameter.Scale; }
+                       set { metaParameter.Scale = value; }
                }
 
-               public int Size {
-                       get { return size; }
-                       set { size = value; }
+                public int Size {
+                       get { return metaParameter.Size; }
+                       set { metaParameter.Size = value; }
                }
 
                public string SourceColumn {
@@ -96,13 +191,367 @@ namespace Mono.Data.TdsClient {
                        get { return sourceVersion; }
                        set { sourceVersion = value; }
                }
+               
+               public TdsType TdsType {
+                       get { return sybaseType; }
+                       set { 
+                               SetTdsType (value); 
+                               isTypeSet = true;
+                       }
+               }
 
                public object Value {
-                       get { return objectValue; }
-                       set { objectValue = value; }
+                       get { return metaParameter.Value; }
+                       set { 
+                               if (!isTypeSet)
+                                       InferTdsType (value);
+                               metaParameter.Value = value; 
+                       }
                }
 
                #endregion // Properties
+
+               #region Methods
+
+               object ICloneable.Clone ()
+               {
+                       return new TdsParameter (ParameterName, TdsType, Size, Direction, IsNullable, Precision, Scale, SourceColumn, SourceVersion, Value);
+               }
+
+               // If the value is set without the DbType/TdsType being set, then we
+               // infer type information.
+               private void InferTdsType (object value)
+               {
+                       Type type = value.GetType ();
+
+                       string exception = String.Format ("The parameter data type of {0} is invalid.", type.Name);
+
+                       switch (type.FullName) {
+                       case "System.Int64":
+                               SetTdsType (TdsType.BigInt);
+                               break;
+                       case "System.Boolean":
+                               SetTdsType (TdsType.Bit);
+                               break;
+                       case "System.String":
+                               SetTdsType (TdsType.NVarChar);
+                               break;
+                       case "System.DateTime":
+                               SetTdsType (TdsType.DateTime);
+                               break;
+                       case "System.Decimal":
+                               SetTdsType (TdsType.Decimal);
+                               break;
+                       case "System.Double":
+                               SetTdsType (TdsType.Float);
+                               break;
+                       case "System.Byte[]":
+                               SetTdsType (TdsType.VarBinary);
+                               break;
+                       case "System.Byte":
+                               SetTdsType (TdsType.TinyInt);
+                               break;
+                       case "System.Int32":
+                               SetTdsType (TdsType.Int);
+                               break;
+                       case "System.Single":
+                               SetTdsType (TdsType.Real);
+                               break;
+                       case "System.Int16":
+                               SetTdsType (TdsType.SmallInt);
+                               break;
+                       case "System.Guid":
+                               SetTdsType (TdsType.UniqueIdentifier);
+                               break;
+                       case "System.Object":
+                               SetTdsType (TdsType.Variant);
+                               break;
+                       default:
+                               throw new ArgumentException (exception);                                
+                       }
+               }
+
+               // When the DbType is set, we also set the TdsType, as well as the SQL Server
+               // string representation of the type name.  If the DbType is not convertible
+               // to an TdsType, throw an exception.
+               private void SetDbType (DbType type)
+               {
+                       string exception = String.Format ("No mapping exists from DbType {0} to a known TdsType.", type);
+
+                       switch (type) {
+                       case DbType.AnsiString:
+                               MetaParameter.TypeName = "varchar";
+                               sybaseType = TdsType.VarChar;
+                               break;
+                       case DbType.AnsiStringFixedLength:
+                               MetaParameter.TypeName = "char";
+                               sybaseType = TdsType.Char;
+                               break;
+                       case DbType.Binary:
+                               MetaParameter.TypeName = "varbinary";
+                               sybaseType = TdsType.VarBinary;
+                               break;
+                       case DbType.Boolean:
+                               MetaParameter.TypeName = "bit";
+                               sybaseType = TdsType.Bit;
+                               break;
+                       case DbType.Byte:
+                               MetaParameter.TypeName = "tinyint";
+                               sybaseType = TdsType.TinyInt;
+                               break;
+                       case DbType.Currency:
+                               sybaseType = TdsType.Money;
+                               MetaParameter.TypeName = "money";
+                               break;
+                       case DbType.Date:
+                       case DbType.DateTime:
+                               MetaParameter.TypeName = "datetime";
+                               sybaseType = TdsType.DateTime;
+                               break;
+                       case DbType.Decimal:
+                               MetaParameter.TypeName = "decimal";
+                               sybaseType = TdsType.Decimal;
+                               break;
+                       case DbType.Double:
+                               MetaParameter.TypeName = "float";
+                               sybaseType = TdsType.Float;
+                               break;
+                       case DbType.Guid:
+                               MetaParameter.TypeName = "uniqueidentifier";
+                               sybaseType = TdsType.UniqueIdentifier;
+                               break;
+                       case DbType.Int16:
+                               MetaParameter.TypeName = "smallint";
+                               sybaseType = TdsType.SmallInt;
+                               break;
+                       case DbType.Int32:
+                               MetaParameter.TypeName = "int";
+                               sybaseType = TdsType.Int;
+                               break;
+                       case DbType.Int64:
+                               MetaParameter.TypeName = "bigint";
+                               sybaseType = TdsType.BigInt;
+                               break;
+                       case DbType.Object:
+                               MetaParameter.TypeName = "sql_variant";
+                               sybaseType = TdsType.Variant;
+                               break;
+                       case DbType.Single:
+                               MetaParameter.TypeName = "real";
+                               sybaseType = TdsType.Real;
+                               break;
+                       case DbType.String:
+                               MetaParameter.TypeName = "nvarchar";
+                               sybaseType = TdsType.NVarChar;
+                               break;
+                       case DbType.StringFixedLength:
+                               MetaParameter.TypeName = "nchar";
+                               sybaseType = TdsType.NChar;
+                               break;
+                       case DbType.Time:
+                               MetaParameter.TypeName = "datetime";
+                               sybaseType = TdsType.DateTime;
+                               break;
+                       default:
+                               throw new ArgumentException (exception);
+                       }
+                       dbType = type;
+               }
+
+               // Used by internal constructor which has a SQL Server typename
+               private void SetDbTypeName (string dbTypeName)
+               {
+                       switch (dbTypeName.ToLower ()) {        
+                       case "bigint":
+                               TdsType = TdsType.BigInt;
+                               break;
+                       case "binary":
+                               TdsType = TdsType.Binary;
+                               break;
+                       case "bit":
+                               TdsType = TdsType.Bit;
+                               break;
+                       case "char":
+                               TdsType = TdsType.Char;
+                               break;
+                       case "datetime":
+                               TdsType = TdsType.DateTime;
+                               break;
+                       case "decimal":
+                               TdsType = TdsType.Decimal;
+                               break;
+                       case "float":
+                               TdsType = TdsType.Float;
+                               break;
+                       case "image":
+                               TdsType = TdsType.Image;
+                               break;
+                       case "int":
+                               TdsType = TdsType.Int;
+                               break;
+                       case "money":
+                               TdsType = TdsType.Money;
+                               break;
+                       case "nchar":
+                               TdsType = TdsType.NChar;
+                               break;
+                       case "ntext":
+                               TdsType = TdsType.NText;
+                               break;
+                       case "nvarchar":
+                               TdsType = TdsType.NVarChar;
+                               break;
+                       case "real":
+                               TdsType = TdsType.Real;
+                               break;
+                       case "smalldatetime":
+                               TdsType = TdsType.SmallDateTime;
+                               break;
+                       case "smallint":
+                               TdsType = TdsType.SmallInt;
+                               break;
+                       case "smallmoney":
+                               TdsType = TdsType.SmallMoney;
+                               break;
+                       case "text":
+                               TdsType = TdsType.Text;
+                               break;
+                       case "timestamp":
+                               TdsType = TdsType.Timestamp;
+                               break;
+                       case "tinyint":
+                               TdsType = TdsType.TinyInt;
+                               break;
+                       case "uniqueidentifier":
+                               TdsType = TdsType.UniqueIdentifier;
+                               break;
+                       case "varbinary":
+                               TdsType = TdsType.VarBinary;
+                               break;
+                       case "varchar":
+                               TdsType = TdsType.VarChar;
+                               break;
+                       default:
+                               TdsType = TdsType.Variant;
+                               break;
+                       }
+               }
+
+               // When the TdsType is set, we also set the DbType, as well as the SQL Server
+               // string representation of the type name.  If the TdsType is not convertible
+               // to a DbType, throw an exception.
+               private void SetTdsType (TdsType type)
+               {
+                       string exception = String.Format ("No mapping exists from TdsType {0} to a known DbType.", type);
+
+                       switch (type) {
+                       case TdsType.BigInt:
+                               MetaParameter.TypeName = "bigint";
+                               dbType = DbType.Int64;
+                               break;
+                       case TdsType.Binary:
+                               MetaParameter.TypeName = "binary";
+                               dbType = DbType.Binary;
+                               break;
+                       case TdsType.Timestamp:
+                               MetaParameter.TypeName = "timestamp";
+                               dbType = DbType.Binary;
+                               break;
+                       case TdsType.VarBinary:
+                               MetaParameter.TypeName = "varbinary";
+                               dbType = DbType.Binary;
+                               break;
+                       case TdsType.Bit:
+                               MetaParameter.TypeName = "bit";
+                               dbType = DbType.Boolean;
+                               break;
+                       case TdsType.Char:
+                               MetaParameter.TypeName = "char";
+                               dbType = DbType.AnsiStringFixedLength;
+                               break;
+                       case TdsType.DateTime:
+                               MetaParameter.TypeName = "datetime";
+                               dbType = DbType.DateTime;
+                               break;
+                       case TdsType.SmallDateTime:
+                               MetaParameter.TypeName = "smalldatetime";
+                               dbType = DbType.DateTime;
+                               break;
+                       case TdsType.Decimal:
+                               MetaParameter.TypeName = "decimal";
+                               dbType = DbType.Decimal;
+                               break;
+                       case TdsType.Float:
+                               MetaParameter.TypeName = "float";
+                               dbType = DbType.Double;
+                               break;
+                       case TdsType.Image:
+                               MetaParameter.TypeName = "image";
+                               dbType = DbType.Binary;
+                               break;
+                       case TdsType.Int:
+                               MetaParameter.TypeName = "int";
+                               dbType = DbType.Int32;
+                               break;
+                       case TdsType.Money:
+                               MetaParameter.TypeName = "money";
+                               dbType = DbType.Currency;
+                               break;
+                       case TdsType.SmallMoney:
+                               MetaParameter.TypeName = "smallmoney";
+                               dbType = DbType.Currency;
+                               break;
+                       case TdsType.NChar:
+                               MetaParameter.TypeName = "nchar";
+                               dbType = DbType.StringFixedLength;
+                               break;
+                       case TdsType.NText:
+                               MetaParameter.TypeName = "ntext";
+                               dbType = DbType.String;
+                               break;
+                       case TdsType.NVarChar:
+                               MetaParameter.TypeName = "nvarchar";
+                               dbType = DbType.String;
+                               break;
+                       case TdsType.Real:
+                               MetaParameter.TypeName = "real";
+                               dbType = DbType.Single;
+                               break;
+                       case TdsType.SmallInt:
+                               MetaParameter.TypeName = "smallint";
+                               dbType = DbType.Int16;
+                               break;
+                       case TdsType.Text:
+                               MetaParameter.TypeName = "text";
+                               dbType = DbType.AnsiString;
+                               break;
+                       case TdsType.VarChar:
+                               MetaParameter.TypeName = "varchar";
+                               dbType = DbType.AnsiString;
+                               break;
+                       case TdsType.TinyInt:
+                               MetaParameter.TypeName = "tinyint";
+                               dbType = DbType.Byte;
+                               break;
+                       case TdsType.UniqueIdentifier:
+                               MetaParameter.TypeName = "uniqueidentifier";
+                               dbType = DbType.Guid;
+                               break;
+                       case TdsType.Variant:
+                               MetaParameter.TypeName = "sql_variant";
+                               dbType = DbType.Object;
+                               break;
+                       default:
+                               throw new ArgumentException (exception);
+                       }
+                       sybaseType = type;
+               }
+
+               public override string ToString() 
+               {
+                       return ParameterName;
+               }
+
+               #endregion // Methods
        }
 }
-
index 326d6f40e319ad09f5741e7deb3169d8280cf34d..c55549b06e87c0018ab8083b2faccc754238877c 100644 (file)
 // Mono.Data.TdsClient.TdsParameterCollection.cs
 //
 // Author:
+//   Rodrigo Moya (rodrigo@ximian.com)
+//   Daniel Morgan (danmorg@sc.rr.com)
 //   Tim Coleman (tim@timcoleman.com)
 //
+// (C) Ximian, Inc 2002
 // Copyright (C) Tim Coleman, 2002
 //
 
-using Mono.Data.Tds.Protocol;
+using Mono.Data.Tds;
 using System;
-using System.Collections;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
-using System.Runtime.InteropServices;
+using System.Collections;
 
 namespace Mono.Data.TdsClient {
+       [ListBindable (false)]
        public sealed class TdsParameterCollection : MarshalByRefObject, IDataParameterCollection, IList, ICollection, IEnumerable
        {
                #region Fields
 
-               ArrayList list = new ArrayList ();
+               ArrayList list = new ArrayList();
+               TdsMetaParameterCollection metaParameters;
+               TdsCommand command;
 
                #endregion // Fields
 
+               #region Constructors
+
+               internal TdsParameterCollection (TdsCommand command)
+               {
+                       this.command = command;
+                       metaParameters = new TdsMetaParameterCollection ();
+               }
+
+               #endregion // Constructors
+
                #region Properties
 
                public int Count {
-                       get { return list.Count; }
+                       get { return list.Count; }                        
                }
 
-               object IList.this [int index] {
-                       get { return (TdsParameter) this[index]; }
-                       set { this[index] = (TdsParameter) value; }
+               public TdsParameter this [int index] {
+                       get { return (TdsParameter) list [index]; }                       
+                       set { list [index] = (TdsParameter) value; }                      
                }
 
-               public TdsParameter this [int index] {
-                       get { 
-                               if (index >= Count)
-                                       throw new IndexOutOfRangeException ();
-                               return (TdsParameter) list[index]; 
-                       }
+               object IDataParameterCollection.this [string parameterName] {
+                       get { return this[parameterName]; }
                        set { 
-                               if (index >= Count)
-                                       throw new IndexOutOfRangeException ();
-                               list[index] = (TdsParameter) value; 
+                               if (!(value is TdsParameter))
+                                       throw new InvalidCastException ("Only SQLParameter objects can be used.");
+                               this [parameterName] = (TdsParameter) value;
                        }
                }
 
-               object IDataParameterCollection.this [string parameterName] {
-                       get { return (TdsParameter) this[parameterName]; }
-                       set { this [parameterName] = (TdsParameter) value; }
+               public TdsParameter this [string parameterName] {
+                       get {
+                               foreach (TdsParameter p in list)
+                                       if (p.ParameterName.Equals (parameterName))
+                                               return p;
+                               throw new IndexOutOfRangeException ("The specified name does not exist: " + parameterName);
+                       }         
+                       set {   
+                               if (!Contains (parameterName))
+                                       throw new IndexOutOfRangeException("The specified name does not exist: " + parameterName);
+                               this [IndexOf (parameterName)] = value;
+                       }                         
                }
 
-               public TdsParameter this [string parameterName] {
-                       get { return this[IndexOf (parameterName)]; }
-                       set { this[IndexOf (parameterName)] = value; }
+               object IList.this [int index] {
+                       get { return (TdsParameter) this [index]; }
+                       set { this [index] = (TdsParameter) value; }
                }
 
                bool IList.IsFixedSize {
-                       get { return false; }
+                       get { return list.IsFixedSize; }
                }
 
                bool IList.IsReadOnly {
-                       get { return false; }
+                       get { return list.IsReadOnly; }
                }
 
                bool ICollection.IsSynchronized {
-                       [MonoTODO]
-                       get { throw new NotImplementedException (); }
+                       get { return list.IsSynchronized; }
                }
 
                object ICollection.SyncRoot {
-                       [MonoTODO]
-                       get { throw new NotImplementedException (); }
+                       get { return list.SyncRoot; }
                }
 
+               internal TdsMetaParameterCollection MetaParameters {
+                       get { return metaParameters; }
+               }
+               
                #endregion // Properties
 
-               #region Methods 
+               #region Methods
 
                public int Add (object value)
                {
                        if (!(value is TdsParameter))
-                               throw new InvalidCastException ();
+                               throw new InvalidCastException ("The parameter was not an TdsParameter.");
                        Add ((TdsParameter) value);
                        return IndexOf (value);
                }
-
+               
                public TdsParameter Add (TdsParameter value)
                {
+                       if (value.Container != null)
+                               throw new ArgumentException ("The TdsParameter specified in the value parameter is already added to this or another TdsParameterCollection.");
+                       
+                       value.Container = this;
                        list.Add (value);
-                       return value; 
+                       metaParameters.Add (value.MetaParameter);
+                       return value;
                }
-
+               
                public TdsParameter Add (string parameterName, object value)
                {
                        return Add (new TdsParameter (parameterName, value));
                }
+               
+               public TdsParameter Add (string parameterName, TdsType sybaseType)
+               {
+                       return Add (new TdsParameter (parameterName, sybaseType));
+               }
 
-               public void Clear ()
+               public TdsParameter Add (string parameterName, TdsType sybaseType, int size)
                {
-                       list.Clear ();
+                       return Add (new TdsParameter (parameterName, sybaseType, size));
                }
 
+               public TdsParameter Add (string parameterName, TdsType sybaseType, int size, string sourceColumn)
+               {
+                       return Add (new TdsParameter (parameterName, sybaseType, size, sourceColumn));
+               }
+
+               public void Clear()
+               {
+                       metaParameters.Clear ();
+                       list.Clear ();
+               }
+               
                public bool Contains (object value)
                {
-                       return list.Contains (value);
+                       if (!(value is TdsParameter))
+                               throw new InvalidCastException ("The parameter was not an TdsParameter.");
+                       return Contains (((TdsParameter) value).ParameterName);
                }
 
                public bool Contains (string value)
                {
-                       return (IndexOf (value) >= 0);
+                       foreach (TdsParameter p in list)
+                               if (p.ParameterName.Equals (value))
+                                       return true;
+                       return false;
                }
 
                public void CopyTo (Array array, int index)
                {
-                       throw new NotImplementedException ();
+                       list.CopyTo (array, index);
                }
 
-               public IEnumerator GetEnumerator ()
+               public IEnumerator GetEnumerator()
                {
                        return list.GetEnumerator ();
                }
-
+               
                public int IndexOf (object value)
                {
-                       return list.IndexOf (value);
+                       if (!(value is TdsParameter))
+                               throw new InvalidCastException ("The parameter was not an TdsParameter.");
+                       return IndexOf (((TdsParameter) value).ParameterName);
                }
-
+               
                public int IndexOf (string parameterName)
                {
-                       for (int i = 0; i < list.Count; i += 1) 
-                               if (((TdsParameter) list[i]).ParameterName == parameterName)
-                                       return i;
-                       return -1;
+                       return list.IndexOf (parameterName);
                }
 
                public void Insert (int index, object value)
@@ -144,11 +191,13 @@ namespace Mono.Data.TdsClient {
 
                public void Remove (object value)
                {
+                       metaParameters.Remove (((TdsParameter) value).MetaParameter);
                        list.Remove (value);
                }
 
                public void RemoveAt (int index)
                {
+                       metaParameters.RemoveAt (index);
                        list.RemoveAt (index);
                }
 
@@ -157,8 +206,6 @@ namespace Mono.Data.TdsClient {
                        RemoveAt (IndexOf (parameterName));
                }
 
-
-               #endregion // Methods
+               #endregion // Methods   
        }
 }
-
index 8f740998bcda4dc0561a3eb1f65a5cdbec457731..a84a60140760f67493125dd9e53658ccc5683ace 100644 (file)
@@ -4,24 +4,25 @@
 // Author:
 //   Tim Coleman (tim@timcoleman.com)
 //
-// Copyright (C) 2002 Tim Coleman
+// Copyright (C) Tim Coleman, 2002
 //
 
-using Mono.Data.Tds.Protocol;
 using System;
-using System.ComponentModel;
 using System.Data;
+using System.Data.Common;
 
 namespace Mono.Data.TdsClient {
-        public class TdsTransaction : Component, ICloneable, IDbTransaction
+       public sealed class TdsTransaction : MarshalByRefObject, IDbTransaction, IDisposable
        {
                #region Fields
 
+               bool disposed = false;
+
                TdsConnection connection;
                IsolationLevel isolationLevel;
                bool isOpen;
 
-               #endregion // Fields
+               #endregion
 
                #region Constructors
 
@@ -29,8 +30,6 @@ namespace Mono.Data.TdsClient {
                {
                        this.connection = connection;
                        this.isolationLevel = isolevel;
-
-                       connection.Tds.ExecuteNonQuery ("BEGIN TRAN");
                        isOpen = true;
                }
 
@@ -38,54 +37,70 @@ namespace Mono.Data.TdsClient {
 
                #region Properties
 
-               TdsConnection Connection {
+               public TdsConnection Connection {
                        get { return connection; }
                }
 
-               IDbConnection IDbTransaction.Connection {
-                       get { return Connection; }
+               internal bool IsOpen {
+                       get { return isOpen; }
                }
 
-               IsolationLevel IDbTransaction.IsolationLevel {
+               public IsolationLevel IsolationLevel {
                        get { return isolationLevel; }
                }
-
-               public bool IsOpen {    
-                       get { return isOpen; }
+               
+               IDbConnection IDbTransaction.Connection {
+                       get { return Connection; }
                }
 
                #endregion // Properties
-
-                #region Methods
+               
+               #region Methods
 
                public void Commit ()
                {
                        if (!isOpen)
-                               throw new InvalidOperationException ("This TdsTransaction has completed; it is no longer usable.");
-                       connection.Tds.ExecuteNonQuery ("IF @@TRANCOUNT>0 COMMIT TRAN");
+                               throw new InvalidOperationException ("The Transaction was not open.");
+                       connection.Tds.Execute ("COMMIT TRANSACTION");
+                       connection.Transaction = null;
                        isOpen = false;
+               }               
+
+               private void Dispose (bool disposing)
+               {
+                       if (!disposed) {
+                               if (disposing)
+                                       Rollback ();
+                               disposed = true;
+                       }
                }
 
-                object ICloneable.Clone()
-                {
-                        throw new NotImplementedException ();
-                }
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
 
                public void Rollback ()
+               {
+                       Rollback (String.Empty);
+               }
+
+               public void Rollback (string transactionName)
                {
                        if (!isOpen)
-                               throw new InvalidOperationException ("This TdsTransaction has completed; it is no longer usable.");
-                       connection.Tds.ExecuteNonQuery ("IF @@TRANCOUNT>0 ROLLBACK TRAN");
+                               throw new InvalidOperationException ("The Transaction was not open.");
+                       connection.Tds.Execute (String.Format ("ROLLBACK TRANSACTION {0}", transactionName));
                        isOpen = false;
                }
 
                public void Save (string savePointName)
                {
                        if (!isOpen)
-                               throw new InvalidOperationException ("This TdsTransaction has completed; it is no longer usable.");
-                       connection.Tds.ExecuteNonQuery (String.Format ("SAVE TRAN {0}", savePointName));
+                               throw new InvalidOperationException ("The Transaction was not open.");
+                       connection.Tds.Execute (String.Format ("SAVE TRANSACTION {0}", savePointName));
                }
 
-                #endregion // Methods
+               #endregion // Methods
        }
 }
index d279d7e7286c69c49bde07da8345b91ec7763576..f6fb0fc96e813fada31ee71ec75ec22e7610bff4 100644 (file)
@@ -15,6 +15,7 @@ using System.Globalization;
 namespace Mono.Data.TdsTypes {
        public struct TdsDecimal : INullable, IComparable
        {
+
                #region Fields
 
                int[] value;
@@ -22,17 +23,18 @@ namespace Mono.Data.TdsTypes {
                byte scale;
                bool positive;
 
-               private bool notNull;
+               bool notNull;
 
                // borrowed from System.Decimal
                const int SCALE_SHIFT = 16;
                const int SIGN_SHIFT = 31;
                const int RESERVED_SS32_BITS = 0x7F00FFFF;
 
-               public static readonly byte MaxPrecision = 38; 
-               public static readonly byte MaxScale = 28;
-               public static readonly TdsDecimal MaxValue = new TdsDecimal (79228162514264337593543950335.0);
-               public static readonly TdsDecimal MinValue = new TdsDecimal (-79228162514264337593543950335.0);
+               public static readonly byte MaxPrecision = 38;
+               public static readonly byte MaxScale = 38;
+
+               public static readonly TdsDecimal MaxValue = new TdsDecimal (MaxPrecision, (byte)0, true, (int)716002642, Int32.MaxValue, (int)1518778966, (int)1262177448);
+               public static readonly TdsDecimal MinValue = new TdsDecimal (MaxPrecision, (byte)0, false, (int)716002642, Int32.MaxValue, (int)1518778966, (int)1262177448);
                public static readonly TdsDecimal Null;
 
                #endregion
@@ -193,6 +195,14 @@ namespace Mono.Data.TdsTypes {
                        throw new NotImplementedException ();
                }
 
+               internal static TdsDecimal FromTdsBigDecimal (TdsBigDecimal x)
+               {
+                       if (x == null)
+                               return Null;
+                       else
+                               return new TdsDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
+                }
+
                public override int GetHashCode ()
                {
                        return (int)this.Value;
index 8578309c68558364575ca235553019e9063c9495..60c8e05726be192002ab70cf56273e20fef6ed99 100644 (file)
@@ -3,7 +3,7 @@ topdir = ../..
 LIBRARY = $(topdir)/class/lib/Mono.Data.TdsClient.dll
 
 LIB_LIST = list
-LIB_FLAGS = -r corlib -r System -r System.Xml -r System.Data.dll -r Mono.Data.Tds
+LIB_FLAGS = -r corlib -r System -r System.Xml -r System.Data -r Mono.Data.Tds -r System.EnterpriseServices
 
 SOURCES_INCLUDE=*.cs
 SOURCES_EXCLUDE=\