Add SqlCredential support -
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / Tds.cs
index 12af0d836699b7d87c5649f09e1e8a4f8b0e34d8..f06932c802620d1fed8f3fcb74fb9d5e0fb1ee26 100644 (file)
@@ -5,11 +5,12 @@
 //   Tim Coleman (tim@timcoleman.com)
 //   Sebastien Pouliot (spouliot@motus.com)
 //   Daniel Morgan (danielmorgan@verizon.net)
+//      Veerapuram Varadhan  (vvaradhan@novell.com)
 //
 // Copyright (C) 2002 Tim Coleman
 // Portions (C) 2003 Motus Technologies Inc. (http://www.motus.com)
 // Portions (C) 2003,2005 Daniel Morgan
-//
+// Portions (C) 2008,2009 Novell Inc. 
 
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 
 using Mono.Security.Protocol.Ntlm;
 using System;
+using System.IO;
 using System.Collections;
 using System.ComponentModel;
 using System.Diagnostics;
 using System.Net.Sockets;
+using System.Globalization;
+using System.Security;
 using System.Text;
+using System.Runtime.InteropServices;
 
-namespace Mono.Data.Tds.Protocol {
-        public abstract class Tds : Component, ITds
+namespace Mono.Data.Tds.Protocol
+{
+       public abstract class Tds
        {
                #region Fields
 
@@ -58,24 +64,29 @@ namespace Mono.Data.Tds.Protocol {
                string databaseProductName;
                string databaseProductVersion;
                int databaseMajorVersion;
+               CultureInfo locale = CultureInfo.InvariantCulture;
+
+               readonly int lifeTime;
+               readonly DateTime created = DateTime.Now;
 
                string charset;
                string language;
 
-               bool connected = false;
+               bool connected;
                bool moreResults;
 
                Encoding encoder;
 //             bool autoCommit;
 
                bool doneProc;
-               TdsDataRow currentRow = null;
+               bool pooling = true;
+               TdsDataRow currentRow;
                TdsDataColumnCollection columns;
 
                ArrayList tableNames;
                ArrayList columnNames;
 
-               TdsMetaParameterCollection parameters;
+               TdsMetaParameterCollection parameters = new TdsMetaParameterCollection ();
 
                bool queryInProgress;
                int cancelsRequested;
@@ -89,14 +100,17 @@ namespace Mono.Data.Tds.Protocol {
 
                int recordsAffected = -1;
 
-               long StreamLength = 0;
-               long StreamIndex = 0;
-               int StreamColumnIndex = 0;
+               long StreamLength;
+               long StreamIndex;
+               int StreamColumnIndex;
 
-               bool sequentialAccess = false;
-               bool isRowRead = false;
-               bool isResultRead = false;
-               bool LoadInProgress = false;
+               bool sequentialAccess;
+               bool isRowRead;
+               bool isResultRead;
+               bool LoadInProgress;
+               byte [] collation;
+
+               internal int poolStatus = 0;
 
                #endregion // Fields
 
@@ -106,6 +120,10 @@ namespace Mono.Data.Tds.Protocol {
                        get { return charset; }
                }
 
+               protected CultureInfo Locale {
+                       get { return locale; }
+               }
+
                public bool DoneProc {
                        get { return doneProc; }
                }
@@ -134,11 +152,16 @@ namespace Mono.Data.Tds.Protocol {
                        get { return dataSource; }
                }
 
-               public bool IsConnected {
-                       get { return connected; }
+               public virtual bool IsConnected {
+                       get { return connected && comm != null && comm.IsConnected (); }
                        set { connected = value; }
                }
 
+               public bool Pooling {
+                       get { return pooling; }
+                       set { pooling = value; }
+               }
+
                public bool MoreResults {
                        get { return moreResults; }
                        set { moreResults = value; }
@@ -180,6 +203,24 @@ namespace Mono.Data.Tds.Protocol {
                        set { sequentialAccess = value; }
                }
 
+               public byte[] Collation {
+                       get {return collation; }
+               }
+
+               public TdsVersion ServerTdsVersion {
+                       get { 
+                               switch (databaseMajorVersion) {
+                               case 4: return TdsVersion.tds42;
+                               case 5: return TdsVersion.tds50;
+                               case 7: return TdsVersion.tds70;
+                               case 8: return TdsVersion.tds80;
+                               case 9: return TdsVersion.tds90;
+                               case 10: return TdsVersion.tds100;
+                               default: return tdsVersion; // return client's version
+                               }
+                       }
+               }
+
                private void SkipRow ()
                {
                        SkipToColumnIndex (Columns.Count);
@@ -199,7 +240,13 @@ namespace Mono.Data.Tds.Protocol {
                                throw new Exception ("Cannot Skip to a colindex less than the curr index");
 
                        while (colIndex != StreamColumnIndex) {
-                               TdsColumnType colType = (TdsColumnType)Columns[StreamColumnIndex]["ColumnType"];
+#if NET_2_0
+                               TdsColumnType? colType = Columns[StreamColumnIndex].ColumnType;
+                               if (colType == null)
+                                       throw new Exception ("Column type unset.");
+#else
+                               TdsColumnType colType = (TdsColumnType) Columns [StreamColumnIndex]["ColumnType"];
+#endif
                                if (!(colType == TdsColumnType.Image ||
                                        colType == TdsColumnType.Text ||
                                        colType == TdsColumnType.NText)) {
@@ -226,7 +273,11 @@ namespace Mono.Data.Tds.Protocol {
                        if (colIndex != StreamColumnIndex)
                                SkipToColumnIndex (colIndex);
 
+#if NET_2_0
+                       object o = GetColumnValue (Columns[colIndex].ColumnType, false, colIndex);
+#else
                        object o = GetColumnValue ((TdsColumnType)Columns[colIndex]["ColumnType"], false, colIndex);
+#endif
                        StreamColumnIndex++;
                        return o;
                }
@@ -234,27 +285,46 @@ namespace Mono.Data.Tds.Protocol {
                public long GetSequentialColumnValue (int colIndex, long fieldIndex, byte[] buffer, int bufferIndex, int size) 
                {
                        if (colIndex < StreamColumnIndex)
-                               throw new InvalidOperationException ("Invalid attempt tp read from column ordinal" + colIndex); 
+                               throw new InvalidOperationException ("Invalid attempt to read from column ordinal" + colIndex);
+                       try {
+                               if (colIndex != StreamColumnIndex)
+                                       SkipToColumnIndex (colIndex);
 
-                       if (colIndex != StreamColumnIndex) 
-                               SkipToColumnIndex (colIndex);
-
-                       if (!LoadInProgress)
-                               BeginLoad ((TdsColumnType)Columns[colIndex]["ColumnType"]);
+                               if (!LoadInProgress) {
+#if NET_2_0
+                                       BeginLoad (Columns[colIndex].ColumnType);
+#else
+                                       BeginLoad ((TdsColumnType)Columns[colIndex]["ColumnType"]);
+#endif
+                               }
 
-                       if (buffer == null) {
-                               return StreamLength;
+                               if (buffer == null)
+                                       return StreamLength;
+                               return LoadData (fieldIndex, buffer, bufferIndex, size);
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
                        }
-                       return LoadData (fieldIndex, buffer, bufferIndex, size);
                }
 
-               private void BeginLoad(TdsColumnType colType) 
+               private void BeginLoad (
+#if NET_2_0
+                       TdsColumnType? colType
+#else
+                       TdsColumnType colType
+#endif
+               ) 
                {
                        if (LoadInProgress)
                                EndLoad ();
 
                        StreamLength = 0;
-               
+
+#if NET_2_0
+                       if (colType == null)
+                               throw new ArgumentNullException ("colType");
+#endif
+
                        switch (colType) {
                        case TdsColumnType.Text :
                        case TdsColumnType.NText:
@@ -262,6 +332,10 @@ namespace Mono.Data.Tds.Protocol {
                                if (Comm.GetByte () != 0) {
                                        Comm.Skip (24);
                                        StreamLength = Comm.GetTdsInt ();
+                               } else {
+                                       // use -2 to indicate that we're dealing
+                                       // with a NULL value
+                                       StreamLength = -2;
                                }
                                break;
                        case TdsColumnType.BigVarChar:
@@ -304,16 +378,26 @@ namespace Mono.Data.Tds.Protocol {
                                return StreamLength;
 
                        if (fieldIndex < StreamIndex)
-                               throw new InvalidOperationException ("field index less than stream pos");
+                               throw new InvalidOperationException (string.Format (
+                                       "Attempting to read at dataIndex '{0}' is " +
+                                       "not allowed as this is less than the " +
+                                       "current position. You must read from " +
+                                       "dataIndex '{1}' or greater.",
+                                       fieldIndex, StreamIndex));
 
                        if (fieldIndex >= (StreamLength + StreamIndex))
                                return 0;
 
-                       // Skip to the index
-                       Comm.Skip ((int) (fieldIndex - StreamIndex));
+                       // determine number of bytes to skip
+                       int skip = (int) (fieldIndex - StreamIndex);
+                       // skip bytes
+                       Comm.Skip (skip);
+                       // update the current position
                        StreamIndex += (fieldIndex - StreamIndex);
+                       // update the remaining length
+                       StreamLength -= skip;
 
-                       // Load the reqd amt of bytes   
+                       // Load the reqd amt of bytes
                        int loadlen = (int) ((size > StreamLength) ? StreamLength : size);
                        byte[] arr = Comm.GetBytes (loadlen, true);
 
@@ -337,11 +421,23 @@ namespace Mono.Data.Tds.Protocol {
                #region Constructors
 
                public Tds (string dataSource, int port, int packetSize, int timeout, TdsVersion tdsVersion)
+                       : this  (dataSource, port, packetSize, timeout, 0, tdsVersion)
+               {
+               }
+
+               public Tds (string dataSource, int port, int packetSize, int timeout, int lifeTime, TdsVersion tdsVersion)
                {
                        this.tdsVersion = tdsVersion;
                        this.packetSize = packetSize;
                        this.dataSource = dataSource;
+                       this.columns = new TdsDataColumnCollection ();
+                       this.lifeTime = lifeTime;
 
+                       InitComm (port, timeout);
+               }
+
+               protected virtual void InitComm (int port, int timeout)
+               {
                        comm = new TdsComm (dataSource, port, packetSize, timeout, tdsVersion);
                }
 
@@ -349,11 +445,34 @@ namespace Mono.Data.Tds.Protocol {
 
                #region Public Methods
 
+               internal bool Expired {
+                       get {
+                               if (lifeTime == 0)
+                                       return false;
+                               return DateTime.Now > (created + TimeSpan.FromSeconds (lifeTime));
+                       }
+               }
+
                internal protected void InitExec () 
                {
-                       // clean up 
+                       // clean up
                        moreResults = true;
                        doneProc = false;
+
+                       // Reset "read" status variables  - used in case of SequentialAccess
+                       isResultRead = false;
+                       isRowRead = false;
+                       StreamLength = 0;
+                       StreamIndex = 0;
+                       StreamColumnIndex = 0;
+                       LoadInProgress = false;
+                       
+                       // Reset more variables
+                       queryInProgress = false;
+                       cancelsRequested = 0;
+                       cancelsProcessed = 0;
+                       recordsAffected = -1;
+                       
                        messages.Clear ();
                        outputParameters.Clear ();
                }
@@ -363,10 +482,15 @@ namespace Mono.Data.Tds.Protocol {
                        if (queryInProgress) {
                                if (cancelsRequested == cancelsProcessed) {
                                        comm.StartPacket (TdsPacketType.Cancel);
-                                       comm.SendPacket ();
+                                       try {
+                                               Comm.SendPacket ();
+                                       } catch (IOException ex) {
+                                               connected = false;
+                                               throw new TdsInternalException ("Server closed the connection.", ex);
+                                       }
                                        cancelsRequested += 1;
                                }
-                       }       
+                       }
                }
        
                public abstract bool Connect (TdsConnectionParameters connectionParameters);
@@ -377,13 +501,17 @@ namespace Mono.Data.Tds.Protocol {
                        return new TdsTimeoutException (0, 0, message, -2, method, dataSource, "Mono TdsClient Data Provider", 0);
                }
 
-               public void Disconnect ()
+               public virtual void Disconnect ()
                {
-                       comm.StartPacket (TdsPacketType.Logoff);
-                       comm.Append ((byte) 0);
-                       comm.SendPacket ();     
-                       comm.Close ();
+                       try {
+                               comm.StartPacket (TdsPacketType.Logoff);
+                               comm.Append ((byte) 0);
+                               comm.SendPacket ();
+                       } catch {
+                               // We're closing the socket anyway
+                       }
                        connected = false;
+                       comm.Close ();
                }
                
                public virtual bool Reset ()
@@ -422,17 +550,49 @@ namespace Mono.Data.Tds.Protocol {
                        throw new NotSupportedException ();
                }
 
+               internal void ExecBulkCopyMetaData (int timeout, bool wantResults)
+               {
+                       moreResults = true;
+                       try {
+                               Comm.SendPacket ();
+                               CheckForData (timeout);
+                               if (!wantResults) 
+                                       SkipToEnd ();
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
+                       }
+               }
+
+               internal void ExecBulkCopy (int timeout, bool wantResults)
+               {
+                       moreResults = true;
+                       try {
+                               Comm.SendPacket ();
+                               CheckForData (timeout);
+                               if (!wantResults) 
+                                       SkipToEnd ();
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
+                       }
+               }
+
                protected void ExecuteQuery (string sql, int timeout, bool wantResults)
                {
                        InitExec ();
 
                        Comm.StartPacket (TdsPacketType.Query);
                        Comm.Append (sql);
-                       Comm.SendPacket ();
-
-                       CheckForData (timeout);
-                       if (!wantResults) 
-                               SkipToEnd ();
+                       try {
+                               Comm.SendPacket ();
+                               CheckForData (timeout);
+                               if (!wantResults) 
+                                       SkipToEnd ();
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
+                       }
                }
 
                protected virtual void ExecRPC (string rpcName, TdsMetaParameterCollection parameters,
@@ -451,10 +611,15 @@ namespace Mono.Data.Tds.Protocol {
                        Comm.Append (rpcNameBytes);
                        Comm.Append (mask);
                        
-                       Comm.SendPacket ();
-                       CheckForData (timeout);
-                       if (!wantResults) 
-                               SkipToEnd ();
+                       try {
+                               Comm.SendPacket ();
+                               CheckForData (timeout);
+                               if (!wantResults) 
+                                       SkipToEnd ();
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
+                       }
                }
 
                public bool NextResult ()
@@ -480,24 +645,21 @@ namespace Mono.Data.Tds.Protocol {
                                        moreResults = false;
                                        break;
                                }
-
                                switch (subType) {
                                case TdsPacketSubType.ColumnInfo:
                                case TdsPacketSubType.ColumnMetadata: 
-                               case TdsPacketSubType.RowFormat: 
+                               case TdsPacketSubType.RowFormat:
                                        byte peek = Comm.Peek ();
                                        done = (peek != (byte) TdsPacketSubType.TableName);
                                        if (done && doneProc && peek == (byte) TdsPacketSubType.Row) {
                                                outputParams = true;
                                                done = false;
                                        }
-
                                        break;
                                case TdsPacketSubType.TableName:
                                //      done = true;
                                        peek = Comm.Peek ();
                                        done = (peek != (byte) TdsPacketSubType.ColumnDetail);
-
                                        break;
                                case TdsPacketSubType.ColumnDetail:
                                        done = true;
@@ -550,7 +712,12 @@ namespace Mono.Data.Tds.Protocol {
 
                public void SkipToEnd ()
                {
-                       while (NextResult ()) { /* DO NOTHING */ }
+                       try {
+                               while (NextResult ()) { /* DO NOTHING */ }
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
+                       }
                }
 
                public virtual void Unprepare (string statementId) 
@@ -581,16 +748,52 @@ namespace Mono.Data.Tds.Protocol {
                        return new TdsInternalErrorMessageEventArgs (new TdsInternalError (theClass, lineNumber, message, number, procedure, server, source, state));
                }
 
-               private object GetColumnValue (TdsColumnType colType, bool outParam)
+               private Encoding GetEncodingFromColumnCollation (int lcid, int sortId)
+               {
+                       if (sortId != 0) 
+                               return TdsCharset.GetEncodingFromSortOrder (sortId);
+                       else
+                               return TdsCharset.GetEncodingFromLCID (lcid);
+               }
+               
+               protected object GetColumnValue (
+#if NET_2_0
+                       TdsColumnType? colType,
+#else
+                       TdsColumnType colType,
+#endif
+                       bool outParam)
                {
                        return GetColumnValue (colType, outParam, -1);
                }
 
-               private object GetColumnValue (TdsColumnType colType, bool outParam, int ordinal)
+               private object GetColumnValue (
+#if NET_2_0
+                       TdsColumnType? colType,
+#else
+                       TdsColumnType colType,
+#endif
+                       bool outParam, int ordinal)
                {
                        int len;
                        object element = null;
+                       Encoding enc = null;
+                       int lcid = 0, sortId = 0;
 
+#if NET_2_0
+                       if (colType == null)
+                               throw new ArgumentNullException ("colType");
+#endif
+                       if (ordinal > -1 && tdsVersion > TdsVersion.tds70) {
+#if NET_2_0
+                               lcid = (int) columns[ordinal].LCID;
+                               sortId = (int) columns[ordinal].SortOrder; 
+#else
+                               lcid = (int) columns[ordinal]["LCID"];
+                               sortId = (int) columns[ordinal]["SortOrder"];
+#endif                         
+                       }
+                       
                        switch (colType) {
                        case TdsColumnType.IntN :
                                if (outParam)
@@ -600,6 +803,7 @@ namespace Mono.Data.Tds.Protocol {
                        case TdsColumnType.Int1 :
                        case TdsColumnType.Int2 :
                        case TdsColumnType.Int4 :
+                       case TdsColumnType.BigInt :
                                element = GetIntValue (colType);
                                break;
                        case TdsColumnType.Image :
@@ -608,35 +812,62 @@ namespace Mono.Data.Tds.Protocol {
                                element = GetImageValue ();
                                break;
                        case TdsColumnType.Text :
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);                    
                                if (outParam) 
                                        comm.Skip (1);
-                               element = GetTextValue (false);
+                               element = GetTextValue (false, enc);
                                break;
                        case TdsColumnType.NText :
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);
                                if (outParam) 
                                        comm.Skip (1);
-                               element = GetTextValue (true);
+                               element = GetTextValue (true, enc);
                                break;
                        case TdsColumnType.Char :
                        case TdsColumnType.VarChar :
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);                    
                                if (outParam)
                                        comm.Skip (1);
-                               element = GetStringValue (false, false);
+                               element = GetStringValue (colType, false, outParam, enc);
                                break;
                        case TdsColumnType.BigVarBinary :
-                               comm.GetTdsShort ();
+                               if (outParam)
+                                       comm.Skip (1);
+                               len = comm.GetTdsShort ();
+                               element = comm.GetBytes (len, true);
+                               break;
+                               /*
+                       case TdsColumnType.BigBinary :
+                               if (outParam)
+                                       comm.Skip (2);
                                len = comm.GetTdsShort ();
                                element = comm.GetBytes (len, true);
                                break;
+                               */
+                       case TdsColumnType.BigBinary :
+                               if (outParam)
+                                       comm.Skip (2);
+                               element = GetBinaryValue ();
+                               break;
+                       case TdsColumnType.BigChar :
                        case TdsColumnType.BigVarChar :
-                               comm.Skip (2);
-                               element = GetStringValue (false, false);
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);                            
+                               if (outParam)
+                                       comm.Skip (2);
+                               element = GetStringValue (colType, false, outParam, enc);
                                break;
                        case TdsColumnType.NChar :
+                       case TdsColumnType.BigNVarChar :
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);                            
+                               if (outParam)
+                                       comm.Skip(2);
+                               element = GetStringValue (colType, true, outParam, enc);
+                               break;
                        case TdsColumnType.NVarChar :
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);                            
                                if (outParam) 
                                        comm.Skip (1);
-                               element = GetStringValue (true, false);
+                               element = GetStringValue (colType, true, outParam, enc);
                                break;
                        case TdsColumnType.Real :
                        case TdsColumnType.Float8 :
@@ -666,11 +897,24 @@ namespace Mono.Data.Tds.Protocol {
                                        scale = comm.GetByte ();
                                }
                                else {
+#if NET_2_0
+                                       precision = (byte) columns[ordinal].NumericPrecision;
+                                       scale = (byte) columns[ordinal].NumericScale;
+#else
                                        precision = (byte) columns[ordinal]["NumericPrecision"];
                                        scale = (byte) columns[ordinal]["NumericScale"];
+#endif
                                }
 
                                element = GetDecimalValue (precision, scale);
+                               
+                               // workaround for fact that TDS 7.0 returns
+                               // bigint as decimal (19,0), and client code
+                               // expects it to be returned as a long
+                               if (scale == 0 && precision <= 19 && tdsVersion == TdsVersion.tds70) {
+                                       if (!(element is System.DBNull))
+                                               element = Convert.ToInt64 (element);
+                               }
                                break;
                        case TdsColumnType.DateTimeN :
                                if (outParam) 
@@ -701,10 +945,13 @@ namespace Mono.Data.Tds.Protocol {
                                break;
                        case TdsColumnType.UniqueIdentifier :
                                if (comm.Peek () != 16) { // If it's null, then what to do?
-                                       /*byte swallowed =*/ comm.GetByte();    
+                                       /*byte swallowed =*/ comm.GetByte();
                                        element = DBNull.Value;
                                        break;
                                }
+                               if (outParam)
+                                       comm.Skip (1);
+                               
                                len = comm.GetByte () & 0xff;
                                if (len > 0) {
                                        byte[] guidBytes = comm.GetBytes (len, true);
@@ -726,7 +973,6 @@ namespace Mono.Data.Tds.Protocol {
                        default :
                                return DBNull.Value;
                        }
-
                        return element;
                }
 
@@ -734,24 +980,35 @@ namespace Mono.Data.Tds.Protocol {
                {
                        int len;
                        object result = DBNull.Value;
-                       if (tdsVersion == TdsVersion.tds70) {
+
+                       if (tdsVersion >= TdsVersion.tds70) {
                                len = comm.GetTdsShort ();
-                               if (len != 0xffff && len > 0)
+                               if (len != 0xffff && len >= 0)
                                        result = comm.GetBytes (len, true);
-                       } 
-                       else {
+                       } else {
                                len = (comm.GetByte () & 0xff);
                                if (len != 0)
                                        result = comm.GetBytes (len, true);
                        }
+
                        return result;
                }
 
-               private object GetDateTimeValue (TdsColumnType type)
+               private object GetDateTimeValue (
+#if NET_2_0
+                       TdsColumnType? type
+#else
+                       TdsColumnType type
+#endif
+               )
                {
                        int len = 0;
                        object result;
-               
+
+#if NET_2_0
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
+#endif
                        switch (type) {
                        case TdsColumnType.DateTime4:
                                len = 4;
@@ -773,15 +1030,15 @@ namespace Mono.Data.Tds.Protocol {
                        case 8 :
                                result = epoch.AddDays (comm.GetTdsInt ());
                                int seconds = comm.GetTdsInt ();
-                               long millis = ((((long) seconds) % 300L) * 1000L) / 300L;
+                               long millis = (long) System.Math.Round (((((long) seconds) % 300L) * 1000L) / 300f);
                                if (seconds != 0 || millis != 0) {
                                        result = ((DateTime) result).AddSeconds (seconds / 300);
                                        result = ((DateTime) result).AddMilliseconds (millis);
                                }
                                break;
                        case 4 :
-                                // MSDN says small datetime is stored in 2 bytes as no of days
-                                // *after* 1/1/1900. so, cast to unsigned short
+                               // MSDN says small datetime is stored in 2 bytes as no of days
+                               // *after* 1/1/1900. so, cast to unsigned short
                                result = epoch.AddDays ((ushort) comm.GetTdsShort ());
                                short minutes = comm.GetTdsShort ();
                                if (minutes != 0) 
@@ -795,14 +1052,16 @@ namespace Mono.Data.Tds.Protocol {
                        return result;
                }
 
-               private object GetDecimalValue (byte precision, byte scale) {
+               private object GetDecimalValue (byte precision, byte scale)
+               {
                        if (tdsVersion < TdsVersion.tds70)
                                return GetDecimalValueTds50 (precision, scale);
                        else
                                return GetDecimalValueTds70 (precision, scale);
                }
                
-               private object GetDecimalValueTds70 (byte precision, byte scale) {
+               private object GetDecimalValueTds70 (byte precision, byte scale)
+               {
                        int[] bits = new int[4] {0,0,0,0};
 
                        int len = (comm.GetByte() & 0xff) - 1;
@@ -810,27 +1069,27 @@ namespace Mono.Data.Tds.Protocol {
                                return DBNull.Value;
                        
                        bool positive = (comm.GetByte () == 1);
-
                        if (len > 16)
                                throw new OverflowException ();
 
                        for (int i = 0, index = 0; i < len && i < 16; i += 4, index += 1) 
                                bits[index] = comm.GetTdsInt ();
-
+                       
                        if (bits [3] != 0) 
                                return new TdsBigDecimal (precision, scale, !positive, bits);
                        else
                                return new Decimal (bits[0], bits[1], bits[2], !positive, scale);
                }
 
-               private object GetDecimalValueTds50 (byte precision, byte scale) {
+               private object GetDecimalValueTds50 (byte precision, byte scale)
+               {
                        int[] bits = new int[4] {0,0,0,0};
 
                        int len = (comm.GetByte() & 0xff);
                        if (len == 0)
                                return DBNull.Value;
 
-                       byte[] dec_bytes=comm.GetBytes(len,false);      
+                       byte[] dec_bytes=comm.GetBytes(len,false);
                
                        byte[] easy=new byte[4];
 
@@ -860,8 +1119,18 @@ namespace Mono.Data.Tds.Protocol {
                        
                }
 
-               private object GetFloatValue (TdsColumnType columnType)
+               private object GetFloatValue (
+#if NET_2_0
+                       TdsColumnType? columnType
+#else
+                       TdsColumnType columnType
+#endif
+               )
                {
+#if NET_2_0
+                       if (columnType == null)
+                               throw new ArgumentNullException ("columnType");
+#endif
                        int columnSize = 0;
 
                        switch (columnType) {
@@ -902,11 +1171,24 @@ namespace Mono.Data.Tds.Protocol {
                        return (comm.GetBytes (len, true));
                }
 
-               private object GetIntValue (TdsColumnType type)
+               private object GetIntValue (
+#if NET_2_0
+                       TdsColumnType? type
+#else
+                       TdsColumnType type
+#endif
+               )
                {
                        int len;
 
+#if NET_2_0
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
+#endif
                        switch (type) {
+                       case TdsColumnType.BigInt :
+                               len = 8;
+                               break;
                        case TdsColumnType.IntN :
                                len = comm.GetByte ();
                                break;
@@ -924,6 +1206,8 @@ namespace Mono.Data.Tds.Protocol {
                        }
 
                        switch (len) {
+                       case 8:
+                               return (comm.GetTdsInt64 ());
                        case 4 :
                                return (comm.GetTdsInt ());
                        case 2 :
@@ -935,12 +1219,20 @@ namespace Mono.Data.Tds.Protocol {
                        }
                }
 
-               [MonoTODO]
-               private object GetMoneyValue (TdsColumnType type)
+               private object GetMoneyValue (
+#if NET_2_0
+                       TdsColumnType? type
+#else
+                       TdsColumnType type
+#endif
+               )
                {
                        int len;
-                       object result = null;
 
+#if NET_2_0
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
+#endif
                        switch (type) {
                        case TdsColumnType.SmallMoney :
                        case TdsColumnType.Money4 :
@@ -957,32 +1249,70 @@ namespace Mono.Data.Tds.Protocol {
                        }
 
                        switch (len) {
-                       case 4:
-                               return new Decimal (Comm.GetTdsInt (), 0, 0, false, 4);
-                       case 8:
+                       case 4: {
+                               int val = Comm.GetTdsInt ();
+                               bool negative = val < 0;
+                               if (negative)
+                                       val = ~(val - 1);
+                               return new Decimal (val, 0, 0, negative, 4);
+                       }
+                       case 8: {
                                int hi = Comm.GetTdsInt ();
                                int lo = Comm.GetTdsInt ();
-                               return new Decimal (lo, hi, 0, false, 4);
+                               bool negative = hi < 0;
+
+                               if (negative) {
+                                       hi = ~hi;
+                                       lo = ~(lo - 1);
+                               }
+                               return new Decimal (lo, hi, 0, negative, 4);
+                       }
                        default:
                                return DBNull.Value;
                        }
                }
 
-               private object GetStringValue (bool wideChars, bool outputParam)
+               protected object GetStringValue (
+#if NET_2_0
+                       TdsColumnType? colType,
+#else
+                       TdsColumnType colType,
+#endif
+                   bool wideChars, bool outputParam, Encoding encoder)
                {
-                       bool shortLen = (tdsVersion == TdsVersion.tds70) && (wideChars || !outputParam);
+                       bool shortLen = false;
+                       Encoding enc = encoder;
+               
+                       if (tdsVersion > TdsVersion.tds70 && outputParam && 
+                           (colType == TdsColumnType.BigChar || colType == TdsColumnType.BigNVarChar || 
+                            colType == TdsColumnType.BigVarChar || colType == TdsColumnType.NChar ||
+                                colType == TdsColumnType.NVarChar)) {
+                               // Read collation for SqlServer 2000 and beyond
+                               byte[] collation;
+                               collation = Comm.GetBytes (5, true);
+                               enc = TdsCharset.GetEncoding (collation);
+                               shortLen = true;
+                       } else {
+                               shortLen = (tdsVersion >= TdsVersion.tds70) && (wideChars || !outputParam);
+                       }
+                       
                        int len = shortLen ? comm.GetTdsShort () : (comm.GetByte () & 0xff);
+                       return GetStringValue (wideChars, len, enc);
+               }
 
+               protected object GetStringValue (bool wideChars, int len, Encoding enc)
+               {
                        if (tdsVersion < TdsVersion.tds70 && len == 0)
                                return DBNull.Value;
+                       
                        else if (len >= 0) {
                                object result;
                                if (wideChars)
-                                       result = comm.GetString (len / 2);
+                                       result = comm.GetString (len / 2, enc);
                                else
-                                       result = comm.GetString (len, false);
+                                       result = comm.GetString (len, false, enc);
                                if (tdsVersion < TdsVersion.tds70 && ((string) result).Equals (" "))
-                                       result = "";
+                                       result = string.Empty;
                                return result;
                        }
                        else
@@ -994,7 +1324,7 @@ namespace Mono.Data.Tds.Protocol {
                        return comm.GetTdsShort ();
                }
 
-               private object GetTextValue (bool wideChars)
+               private object GetTextValue (bool wideChars, Encoding encoder)
                {
                        string result = null;
                        byte hasValue = comm.GetByte ();
@@ -1011,18 +1341,40 @@ namespace Mono.Data.Tds.Protocol {
                        // this method is called only for Text and NText. Hence will
                        // return a empty string
                        if (len == 0)
-                               return "";
+                               return string.Empty;
 
                        if (wideChars)
-                               result = comm.GetString (len / 2);
+                               result = comm.GetString (len / 2, encoder);
                        else
-                               result = comm.GetString (len, false);
+                               result = comm.GetString (len, false, encoder);
                                len /= 2;
 
                        if ((byte) tdsVersion < (byte) TdsVersion.tds70 && result == " ")
-                               result = "";
+                               result = string.Empty;
 
-                       return result;
+                       return result;                  
+               }
+               
+               internal bool IsBlobType (TdsColumnType columnType)
+               {
+                       return (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image || columnType == TdsColumnType.NText);
+               }
+
+               internal bool IsLargeType (TdsColumnType columnType)
+               {
+                       return ((byte) columnType > 128);
+               }
+
+               protected bool IsWideType (TdsColumnType columnType)
+               {
+                       switch (columnType) {
+                       case TdsColumnType.NChar:
+                       case TdsColumnType.NText:
+                       case TdsColumnType.NVarChar:
+                               return true;
+                       default:
+                               return false;
+                       }
                }
 
                internal static bool IsFixedSizeColumn (TdsColumnType columnType)
@@ -1031,6 +1383,7 @@ namespace Mono.Data.Tds.Protocol {
                                case TdsColumnType.Int1 :
                                case TdsColumnType.Int2 :
                                case TdsColumnType.Int4 :
+                               case TdsColumnType.BigInt :
                                case TdsColumnType.Float8 :
                                case TdsColumnType.DateTime :
                                case TdsColumnType.Bit :
@@ -1039,24 +1392,11 @@ namespace Mono.Data.Tds.Protocol {
                                case TdsColumnType.SmallMoney :
                                case TdsColumnType.Real :
                                case TdsColumnType.DateTime4 :
+                                 /*
+                               case TdsColumnType.Decimal:
+                               case TdsColumnType.Numeric:
+                                 */
                                        return true;
-                               case TdsColumnType.IntN :
-                               case TdsColumnType.MoneyN :
-                               case TdsColumnType.VarChar :
-                               case TdsColumnType.NVarChar :
-                               case TdsColumnType.DateTimeN :
-                               case TdsColumnType.FloatN :
-                               case TdsColumnType.Char :
-                               case TdsColumnType.NChar :
-                               case TdsColumnType.NText :
-                               case TdsColumnType.Image :
-                               case TdsColumnType.VarBinary :
-                               case TdsColumnType.Binary :
-                               case TdsColumnType.Decimal :
-                               case TdsColumnType.Numeric :
-                               case TdsColumnType.BitN :
-                               case TdsColumnType.UniqueIdentifier :
-                                       return false;
                                default :
                                        return false;
                        }
@@ -1076,7 +1416,11 @@ namespace Mono.Data.Tds.Protocol {
 
                        int i = 0;
                        foreach (TdsDataColumn column in columns) {
-                               object o = GetColumnValue ((TdsColumnType) column["ColumnType"], false, i);
+#if NET_2_0
+                               object o = GetColumnValue (column.ColumnType, false, i);
+#else
+                               object o = GetColumnValue ((TdsColumnType)column["ColumnType"], false, i);
+#endif
                                currentRow.Add (o);
                                if (doneProc)
                                        outputParameters.Add (o);
@@ -1104,41 +1448,13 @@ namespace Mono.Data.Tds.Protocol {
                                case TdsColumnType.Float8 :
                                case TdsColumnType.DateTime :
                                case TdsColumnType.Money :
+                               case TdsColumnType.BigInt :
                                        return 8;
                                default :
                                        return 0;
                        }
                }
 
-               private int LookupDisplaySize (TdsColumnType columnType) 
-               {
-                       switch (columnType) {
-                               case TdsColumnType.Int1 :
-                                       return 3;
-                               case TdsColumnType.Int2 :
-                                       return 6;
-                               case TdsColumnType.Int4 :
-                                       return 11;
-                               case TdsColumnType.Real :
-                                       return 14;
-                               case TdsColumnType.Float8 :
-                                       return 24;
-                               case TdsColumnType.DateTime :
-                                       return 23;
-                               case TdsColumnType.DateTime4 :
-                                       return 16;
-                               case TdsColumnType.Bit :
-                                       return 1;
-                               case TdsColumnType.Money :
-                                       return 21;
-                               case TdsColumnType.Money4 :
-                               case TdsColumnType.SmallMoney :
-                                       return 12;
-                               default:
-                                       return 0;
-                       }
-               }
-
                protected internal int ProcessAuthentication ()
                {
                        int pdu_size = Comm.GetTdsShort ();
@@ -1149,17 +1465,21 @@ namespace Mono.Data.Tds.Protocol {
                        // 0x0200       Negotiate NTLM
                        // 0x8000       Negotiate Always Sign
 
-                       Type3Message t3 = new Type3Message ();
-                       t3.Challenge = t2.Nonce;
+                       Type3Message t3 = new Type3Message (t2);
                        
                        t3.Domain = this.connectionParms.DefaultDomain;
                        t3.Host = this.connectionParms.Hostname;
                        t3.Username = this.connectionParms.User;
-                       t3.Password = this.connectionParms.Password;
+                       t3.Password = GetPlainPassword(this.connectionParms.Password);
 
                        Comm.StartPacket (TdsPacketType.SspAuth); // 0x11
                        Comm.Append (t3.GetBytes ());
-                       Comm.SendPacket ();
+                       try {
+                               Comm.SendPacket ();
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
+                       }
                        return 1; // TDS_SUCCEED
                }
 
@@ -1178,7 +1498,7 @@ namespace Mono.Data.Tds.Protocol {
 
                                bool isAlias = ((values[2] & (byte) TdsColumnStatus.Rename) != 0);
                                if (isAlias) {
-                                       if (tdsVersion == TdsVersion.tds70) {
+                                       if (tdsVersion >= TdsVersion.tds70) {
                                                columnNameLength = comm.GetByte ();
                                                position += 2 * columnNameLength + 1;
                                        }
@@ -1193,17 +1513,26 @@ namespace Mono.Data.Tds.Protocol {
                                byte tableIndex = (byte) (values[1] - (byte) 1);
                                bool isExpression = ((values[2] & (byte) TdsColumnStatus.IsExpression) != 0);
 
-                               columns [index]["IsExpression"] = isExpression;
-                               columns [index]["IsKey"] = ((values[2] & (byte) TdsColumnStatus.IsKey) != 0);
-                               columns [index]["IsHidden"] = ((values[2] & (byte) TdsColumnStatus.Hidden) != 0);
-                               columns [index]["IsAliased"] = isAlias;
-
-                               columns [index]["BaseColumnName"] = ((isAlias) ? baseColumnName : null);
-                               columns [index]["BaseTableName"] = ((!isExpression) ? tableNames [tableIndex] : null);
+                               TdsDataColumn column = columns [index];
+#if NET_2_0
+                               column.IsHidden = ((values[2] & (byte) TdsColumnStatus.Hidden) != 0);
+                               column.IsExpression = isExpression;
+                               column.IsKey = ((values[2] & (byte) TdsColumnStatus.IsKey) != 0);
+                               column.IsAliased = isAlias;
+                               column.BaseColumnName = ((isAlias) ? baseColumnName : null);
+                               column.BaseTableName = ((!isExpression) ? (string) tableNames [tableIndex] : null);
+#else
+                               column ["IsHidden"] = ((values [2] & (byte) TdsColumnStatus.Hidden) != 0);
+                               column ["IsExpression"] = isExpression;
+                               column ["IsKey"] = ((values [2] & (byte) TdsColumnStatus.IsKey) != 0);
+                               column ["IsAliased"] = isAlias;
+                               column ["BaseColumnName"] = ((isAlias) ? baseColumnName : null);
+                               column ["BaseTableName"] = ((!isExpression) ? tableNames [tableIndex] : null);
+#endif
                        }
                }
 
-               protected abstract TdsDataColumnCollection ProcessColumnInfo ();
+               protected abstract void ProcessColumnInfo ();
 
                protected void ProcessColumnNames ()
                {
@@ -1231,7 +1560,6 @@ namespace Mono.Data.Tds.Protocol {
                        Comm.Skip (1);
 
                        int rowCount = comm.GetTdsInt ();
-
                        bool validRowCount = IsValidRowCount (status,op);
                        moreResults = ((status & 0x01) != 0);
                        bool cancelled = ((status & 0x20) != 0);
@@ -1261,6 +1589,8 @@ namespace Mono.Data.Tds.Protocol {
 
                protected void ProcessEnvironmentChange ()
                {
+                       // VARADHAN: TDS 8 Debugging
+                       //Console.WriteLine ("In ProcessEnvironmentChange... entry");
                        int len = GetSubPacketLength ();
                        TdsEnvPacketSubType type = (TdsEnvPacketSubType) comm.GetByte ();
                        int cLen;
@@ -1268,10 +1598,10 @@ namespace Mono.Data.Tds.Protocol {
                        switch (type) {
                        case TdsEnvPacketSubType.BlockSize :
                                string blockSize;
-                               cLen = comm.GetByte () & 0xff;
+                               cLen = comm.GetByte ();
                                blockSize = comm.GetString (cLen);
 
-                               if (tdsVersion == TdsVersion.tds70) 
+                               if (tdsVersion >= TdsVersion.tds70) 
                                        comm.Skip (len - 2 - cLen * 2);
                                else 
                                        comm.Skip (len - 2 - cLen);
@@ -1280,7 +1610,7 @@ namespace Mono.Data.Tds.Protocol {
                                comm.ResizeOutBuf (packetSize);
                                break;
                        case TdsEnvPacketSubType.CharSet :
-                               cLen = comm.GetByte () & 0xff;
+                               cLen = comm.GetByte ();
                                if (tdsVersion == TdsVersion.tds70) {
                                        SetCharset (comm.GetString (cLen));
                                        comm.Skip (len - 2 - cLen * 2);
@@ -1290,9 +1620,22 @@ namespace Mono.Data.Tds.Protocol {
                                        comm.Skip (len - 2 - cLen);
                                }
 
+                               break;
+                       case TdsEnvPacketSubType.Locale :
+                               cLen = comm.GetByte ();
+                               int lcid = 0;
+                               if (tdsVersion >= TdsVersion.tds70) {
+                                       lcid = (int) Convert.ChangeType (comm.GetString (cLen), typeof (int));
+                                       comm.Skip (len - 2 - cLen * 2);
+                               }
+                               else {
+                                       lcid = (int) Convert.ChangeType (comm.GetString (cLen), typeof (int));
+                                       comm.Skip (len - 2 - cLen);
+                               }
+                               locale = new CultureInfo (lcid);
                                break;
                        case TdsEnvPacketSubType.Database :
-                               cLen = comm.GetByte () & 0xff;
+                               cLen = comm.GetByte ();
                                string newDB = comm.GetString (cLen);
                                cLen = comm.GetByte () & 0xff;
                                comm.GetString (cLen);
@@ -1300,26 +1643,60 @@ namespace Mono.Data.Tds.Protocol {
                                        originalDatabase = newDB;
                                database = newDB;
                                break;
+                       case TdsEnvPacketSubType.CollationInfo:
+                               //Console.WriteLine ("ProcessEnvironmentChange::Got collation info");
+                               cLen = comm.GetByte ();
+                               collation = comm.GetBytes (cLen, true);
+                               lcid = TdsCollation.LCID (collation);
+                               locale = new CultureInfo (lcid);
+                               SetCharset (TdsCharset.GetEncoding (collation));
+                               break;
+                               
                        default:
                                comm.Skip (len - 1);
                                break;
                        }
+                       // VARADHAN: TDS 8 Debugging
+                       //Console.WriteLine ("In ProcessEnvironmentChange... exit");
                }
 
                protected void ProcessLoginAck ()
                {
+                       uint srvVersion = 0;
                        GetSubPacketLength ();
+                       
+                       //Console.WriteLine ("ProcessLoginAck: B4 tdsVersion:{0}", tdsVersion);
+                       // Valid only for a Login7 request
+                       if (tdsVersion >= TdsVersion.tds70) {
+                               comm.Skip (1);
+                               srvVersion = (uint)comm.GetTdsInt ();
 
-                       if (tdsVersion == TdsVersion.tds70) {
-                               comm.Skip (5);
+                               //Console.WriteLine ("srvVersion: {0}", srvVersion);
+                               switch (srvVersion) {
+                               case 0x00000007: 
+                                       tdsVersion = TdsVersion.tds70;
+                                       break;
+                               case 0x00000107:
+                                       tdsVersion = TdsVersion.tds80;
+                                       break;
+                               case 0x01000071:
+                                       tdsVersion = TdsVersion.tds81;
+                                       break;
+                               case 0x02000972:
+                                       tdsVersion = TdsVersion.tds90;
+                                       break;
+                               }
+                               //Console.WriteLine ("ProcessLoginAck: after tdsVersion:{0}", tdsVersion);                              
+                       }
+                       
+                       if (tdsVersion >= TdsVersion.tds70) {
                                int nameLength = comm.GetByte ();
                                databaseProductName = comm.GetString (nameLength);
                                databaseMajorVersion = comm.GetByte ();
                                databaseProductVersion = String.Format ("{0}.{1}.{2}", databaseMajorVersion.ToString("00"),
                                                                comm.GetByte ().ToString("00"), 
                                                                (256 * comm.GetByte () + comm.GetByte ()).ToString("0000"));
-                       }
-                       else {
+                       } else {
                                comm.Skip (5);
                                short nameLength = comm.GetByte ();
                                databaseProductName = comm.GetString (nameLength);
@@ -1335,6 +1712,7 @@ namespace Mono.Data.Tds.Protocol {
                        }
 
                        connected = true;
+                       //Console.WriteLine ("databaseProductVersion:{0}", databaseProductVersion);
                }
 
                protected void OnTdsErrorMessage (TdsInternalErrorMessageEventArgs e)
@@ -1385,15 +1763,14 @@ namespace Mono.Data.Tds.Protocol {
                                messages.Add (new TdsInternalError (theClass, lineNumber, message, number, procedure, server, source, state));
                }
 
-               protected void ProcessOutputParam ()
+               protected virtual void ProcessOutputParam ()
                {
                        GetSubPacketLength ();
-                       comm.GetString (comm.GetByte () & 0xff);
+                       /*string paramName = */comm.GetString (comm.GetByte () & 0xff);
                        comm.Skip (5);
 
                        TdsColumnType colType = (TdsColumnType) comm.GetByte ();
                        object value = GetColumnValue (colType, true);
-
                        outputParameters.Add (value);
                }
 
@@ -1407,8 +1784,13 @@ namespace Mono.Data.Tds.Protocol {
 
                protected virtual TdsPacketSubType ProcessSubPacket ()
                {
+                       // VARADHAN: TDS 8 Debugging
+                       // Console.WriteLine ("In ProcessSubPacket... entry");
+                       
                        TdsPacketSubType subType = (TdsPacketSubType) comm.GetByte ();
 
+                       // VARADHAN: TDS 8 Debugging
+                       //Console.WriteLine ("Subpacket type: {0}", subType);
                        switch (subType) {
                        case TdsPacketSubType.Dynamic2:
                                comm.Skip (comm.GetTdsInt ());
@@ -1440,7 +1822,7 @@ namespace Mono.Data.Tds.Protocol {
                                ProcessAuthentication ();
                                break;
                        case TdsPacketSubType.ReturnStatus :
-                               Comm.Skip (4);
+                               ProcessReturnStatus ();
                                break;
                        case TdsPacketSubType.ProcId:
                                Comm.Skip (8);
@@ -1457,7 +1839,8 @@ namespace Mono.Data.Tds.Protocol {
                        case TdsPacketSubType.ColumnInfo:      // TDS 4.2
                        case TdsPacketSubType.ColumnMetadata:  // TDS 7.0
                        case TdsPacketSubType.RowFormat:       // TDS 5.0
-                               columns = ProcessColumnInfo ();
+                               Columns.Clear ();
+                               ProcessColumnInfo ();
                                break;
                        case TdsPacketSubType.ColumnDetail:
                                ProcessColumnDetail ();
@@ -1476,6 +1859,8 @@ namespace Mono.Data.Tds.Protocol {
                                break;
                        }
 
+                       // VARADHAN: TDS 8 Debugging
+                       //Console.WriteLine ("In ProcessSubPacket... exit");
                        return subType;
                }
 
@@ -1487,7 +1872,7 @@ namespace Mono.Data.Tds.Protocol {
                        int len;
 
                        while (position < totalLength) {
-                               if (tdsVersion == TdsVersion.tds70) {
+                               if (tdsVersion >= TdsVersion.tds70) {
                                        len = comm.GetTdsShort ();
                                        position += 2 * (len + 1);
                                }
@@ -1496,9 +1881,14 @@ namespace Mono.Data.Tds.Protocol {
                                        position += len + 1;
                                }
                                tableNames.Add (comm.GetString (len));
-                       }       
+                       }
                }
 
+               protected void SetCharset (Encoding encoder)
+               {
+                       comm.Encoder = encoder;
+               }
+               
                protected void SetCharset (string charset)
                {
                        if (charset == null || charset.Length > 30)
@@ -1515,7 +1905,7 @@ namespace Mono.Data.Tds.Protocol {
                                encoder = Encoding.GetEncoding ("iso-8859-1");
                                this.charset = "iso_1";
                        }
-                       comm.Encoder = encoder;
+                       SetCharset (encoder);
                }
 
                protected void SetLanguage (string language)
@@ -1526,6 +1916,25 @@ namespace Mono.Data.Tds.Protocol {
                        this.language = language;
                }
 
+               protected virtual void ProcessReturnStatus () 
+               {
+                       comm.Skip(4);
+               }
+
+               public static string GetPlainPassword(SecureString secPass)
+               {
+                       IntPtr plainString = IntPtr.Zero;
+                       try
+                       {
+                               plainString = Marshal.SecureStringToGlobalAllocUnicode(secPass);
+                               return Marshal.PtrToStringUni(plainString);
+                       }
+                       finally
+                       {
+                               Marshal.ZeroFreeGlobalAllocUnicode(plainString);
+                       }
+               }
+
                #endregion // Private Methods
 
 #if NET_2_0
@@ -1540,10 +1949,15 @@ namespace Mono.Data.Tds.Protocol {
 
                        Comm.StartPacket (TdsPacketType.Query);
                        Comm.Append (sql);
-                       Comm.SendPacket ();
+                       try {
+                               Comm.SendPacket ();
+                               Comm.BeginReadPacket (new AsyncCallback(OnBeginExecuteQueryCallback), 
+                                                     ar);
+                       } catch (IOException ex) {
+                               connected = false;
+                               throw new TdsInternalException ("Server closed the connection.", ex);
+                       }
 
-                        Comm.BeginReadPacket (new AsyncCallback(OnBeginExecuteQueryCallback), 
-                                                                    ar);
                         return ar;
                 }