Merge pull request #2394 from Mailaender/patch-1
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / Tds.cs
index d00b4851458e04afa3e425487432590e9b84c558..5cb0ae8a4ce2ab27e74207542e28e31427e4efe8 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
@@ -40,7 +41,9 @@ 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
 {
@@ -63,6 +66,9 @@ namespace Mono.Data.Tds.Protocol
                int databaseMajorVersion;
                CultureInfo locale = CultureInfo.InvariantCulture;
 
+               readonly int lifeTime;
+               readonly DateTime created = DateTime.Now;
+
                string charset;
                string language;
 
@@ -102,6 +108,7 @@ namespace Mono.Data.Tds.Protocol
                bool isRowRead;
                bool isResultRead;
                bool LoadInProgress;
+               byte [] collation;
 
                internal int poolStatus = 0;
 
@@ -145,8 +152,8 @@ 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; }
                }
 
@@ -196,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);
@@ -215,7 +240,9 @@ namespace Mono.Data.Tds.Protocol
                                throw new Exception ("Cannot Skip to a colindex less than the curr index");
 
                        while (colIndex != StreamColumnIndex) {
-                               TdsColumnType colType = Columns[StreamColumnIndex].ColumnType;
+                               TdsColumnType? colType = Columns[StreamColumnIndex].ColumnType;
+                               if (colType == null)
+                                       throw new Exception ("Column type unset.");
                                if (!(colType == TdsColumnType.Image ||
                                        colType == TdsColumnType.Text ||
                                        colType == TdsColumnType.NText)) {
@@ -250,17 +277,17 @@ 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) 
+                               if (colIndex != StreamColumnIndex)
                                        SkipToColumnIndex (colIndex);
 
-                               if (!LoadInProgress)
+                               if (!LoadInProgress) {
                                        BeginLoad (Columns[colIndex].ColumnType);
+                               }
 
-                               if (buffer == null) {
+                               if (buffer == null)
                                        return StreamLength;
-                               }
                                return LoadData (fieldIndex, buffer, bufferIndex, size);
                        } catch (IOException ex) {
                                connected = false;
@@ -268,13 +295,18 @@ namespace Mono.Data.Tds.Protocol
                        }
                }
 
-               private void BeginLoad(TdsColumnType colType) 
+               private void BeginLoad (
+                       TdsColumnType? colType
+               ) 
                {
                        if (LoadInProgress)
                                EndLoad ();
 
                        StreamLength = 0;
-               
+
+                       if (colType == null)
+                               throw new ArgumentNullException ("colType");
+
                        switch (colType) {
                        case TdsColumnType.Text :
                        case TdsColumnType.NText:
@@ -282,6 +314,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:
@@ -324,16 +360,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);
 
@@ -357,11 +403,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);
                }
 
@@ -369,11 +427,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 ();
                }
@@ -402,13 +483,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 ()
@@ -645,16 +730,37 @@ 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 (
+                       TdsColumnType? colType,
+                       bool outParam)
                {
                        return GetColumnValue (colType, outParam, -1);
                }
 
-               private object GetColumnValue (TdsColumnType colType, bool outParam, int ordinal)
+               private object GetColumnValue (
+                       TdsColumnType? colType,
+                       bool outParam, int ordinal)
                {
                        int len;
                        object element = null;
-
+                       Encoding enc = null;
+                       int lcid = 0, sortId = 0;
+
+                       if (colType == null)
+                               throw new ArgumentNullException ("colType");
+                       if (ordinal > -1 && tdsVersion > TdsVersion.tds70) {
+                               lcid = (int) columns[ordinal].LCID;
+                               sortId = (int) columns[ordinal].SortOrder; 
+                       }
+                       
                        switch (colType) {
                        case TdsColumnType.IntN :
                                if (outParam)
@@ -664,6 +770,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 :
@@ -672,20 +779,23 @@ 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 :
                                if (outParam)
@@ -708,20 +818,23 @@ namespace Mono.Data.Tds.Protocol
                                break;
                        case TdsColumnType.BigChar :
                        case TdsColumnType.BigVarChar :
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);                            
                                if (outParam)
                                        comm.Skip (2);
-                               element = GetStringValue (false, false);
+                               element = GetStringValue (colType, false, outParam, enc);
                                break;
                        case TdsColumnType.NChar :
                        case TdsColumnType.BigNVarChar :
+                               enc = GetEncodingFromColumnCollation (lcid, sortId);                            
                                if (outParam)
                                        comm.Skip(2);
-                               element = GetStringValue (true, false);
+                               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 :
@@ -751,8 +864,8 @@ namespace Mono.Data.Tds.Protocol
                                        scale = comm.GetByte ();
                                }
                                else {
-                                       precision = (byte) columns[ordinal]["NumericPrecision"];
-                                       scale = (byte) columns[ordinal]["NumericScale"];
+                                       precision = (byte) columns[ordinal].NumericPrecision;
+                                       scale = (byte) columns[ordinal].NumericScale;
                                }
 
                                element = GetDecimalValue (precision, scale);
@@ -760,7 +873,7 @@ namespace Mono.Data.Tds.Protocol
                                // 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) {
+                               if (scale == 0 && precision <= 19 && tdsVersion == TdsVersion.tds70) {
                                        if (!(element is System.DBNull))
                                                element = Convert.ToInt64 (element);
                                }
@@ -819,6 +932,11 @@ namespace Mono.Data.Tds.Protocol
                                        element = new Guid (guidBytes);
                                }
                                break;
+                       case TdsColumnType.Variant :
+                               if (outParam)
+                                       comm.Skip (4);
+                               element = GetVariantValue();
+                               break;
                        default :
                                return DBNull.Value;
                        }
@@ -830,9 +948,9 @@ 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 {
                                len = (comm.GetByte () & 0xff);
@@ -843,11 +961,49 @@ namespace Mono.Data.Tds.Protocol
                        return result;
                }
 
-               private object GetDateTimeValue (TdsColumnType type)
+               private object GetVariantValue ()
+               {
+                       uint len = (uint)comm.GetTdsInt ();
+                       if (len == 0)
+                               return DBNull.Value;
+
+                       // VARIANT_BASETYPE
+                       TdsColumnType colType = (TdsColumnType)comm.GetByte ();
+                       // VARIANT_PROPBYTES
+                       byte propbytes = comm.GetByte ();
+                       if (propbytes != 0)
+                               // VARIANT_PROPERTIES
+                               comm.Skip (propbytes);
+
+                       len -= (uint)propbytes + 2;
+
+                       switch (colType)
+                       {
+                       case TdsColumnType.Int1 :
+                       case TdsColumnType.Int2 :
+                       case TdsColumnType.Int4 :
+                       case TdsColumnType.BigInt :
+                               return GetIntValue (colType);
+                       default:
+                               // The old code was ignoring variants
+                               // and returning null.  Should we
+                               // throw an exception?
+                               comm.Skip (len);
+                               break;
+                       }
+
+                       return DBNull.Value;
+               }
+
+               private object GetDateTimeValue (
+                       TdsColumnType? type
+               )
                {
                        int len = 0;
                        object result;
-               
+
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
                        switch (type) {
                        case TdsColumnType.DateTime4:
                                len = 4;
@@ -958,8 +1114,12 @@ namespace Mono.Data.Tds.Protocol
                        
                }
 
-               private object GetFloatValue (TdsColumnType columnType)
+               private object GetFloatValue (
+                       TdsColumnType? columnType
+               )
                {
+                       if (columnType == null)
+                               throw new ArgumentNullException ("columnType");
                        int columnSize = 0;
 
                        switch (columnType) {
@@ -1000,11 +1160,18 @@ namespace Mono.Data.Tds.Protocol
                        return (comm.GetBytes (len, true));
                }
 
-               private object GetIntValue (TdsColumnType type)
+               private object GetIntValue (
+                       TdsColumnType? type
+               )
                {
                        int len;
 
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
                        switch (type) {
+                       case TdsColumnType.BigInt :
+                               len = 8;
+                               break;
                        case TdsColumnType.IntN :
                                len = comm.GetByte ();
                                break;
@@ -1022,6 +1189,8 @@ namespace Mono.Data.Tds.Protocol
                        }
 
                        switch (len) {
+                       case 8:
+                               return (comm.GetTdsInt64 ());
                        case 4 :
                                return (comm.GetTdsInt ());
                        case 2 :
@@ -1033,10 +1202,14 @@ namespace Mono.Data.Tds.Protocol
                        }
                }
 
-               private object GetMoneyValue (TdsColumnType type)
+               private object GetMoneyValue (
+                       TdsColumnType? type
+               )
                {
                        int len;
 
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
                        switch (type) {
                        case TdsColumnType.SmallMoney :
                        case TdsColumnType.Money4 :
@@ -1053,30 +1226,64 @@ 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 (
+                       TdsColumnType? colType,
+                   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 = string.Empty;
                                return result;
@@ -1090,7 +1297,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 ();
@@ -1110,20 +1317,20 @@ namespace Mono.Data.Tds.Protocol
                                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 = string.Empty;
 
-                       return result;
+                       return result;                  
                }
-
+               
                internal bool IsBlobType (TdsColumnType columnType)
                {
-                       return (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image || columnType == TdsColumnType.NText);
+                       return (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image || columnType == TdsColumnType.NText || columnType == TdsColumnType.Variant);
                }
 
                internal bool IsLargeType (TdsColumnType columnType)
@@ -1131,12 +1338,25 @@ namespace Mono.Data.Tds.Protocol
                        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)
                {
                        switch (columnType) {
                                case TdsColumnType.Int1 :
                                case TdsColumnType.Int2 :
                                case TdsColumnType.Int4 :
+                               case TdsColumnType.BigInt :
                                case TdsColumnType.Float8 :
                                case TdsColumnType.DateTime :
                                case TdsColumnType.Bit :
@@ -1197,41 +1417,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 ();
@@ -1242,13 +1434,12 @@ 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 ());
@@ -1276,7 +1467,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;
                                        }
@@ -1291,17 +1482,17 @@ 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];
+                               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);
                        }
                }
 
-               protected abstract TdsDataColumnCollection ProcessColumnInfo ();
+               protected abstract void ProcessColumnInfo ();
 
                protected void ProcessColumnNames ()
                {
@@ -1358,6 +1549,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;
@@ -1368,7 +1561,7 @@ namespace Mono.Data.Tds.Protocol
                                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);
@@ -1391,7 +1584,7 @@ namespace Mono.Data.Tds.Protocol
                        case TdsEnvPacketSubType.Locale :
                                cLen = comm.GetByte ();
                                int lcid = 0;
-                               if (tdsVersion == TdsVersion.tds70) {
+                               if (tdsVersion >= TdsVersion.tds70) {
                                        lcid = (int) Convert.ChangeType (comm.GetString (cLen), typeof (int));
                                        comm.Skip (len - 2 - cLen * 2);
                                }
@@ -1410,26 +1603,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);
@@ -1445,6 +1672,7 @@ namespace Mono.Data.Tds.Protocol
                        }
 
                        connected = true;
+                       //Console.WriteLine ("databaseProductVersion:{0}", databaseProductVersion);
                }
 
                protected void OnTdsErrorMessage (TdsInternalErrorMessageEventArgs e)
@@ -1495,7 +1723,7 @@ 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 ();
                        /*string paramName = */comm.GetString (comm.GetByte () & 0xff);
@@ -1516,8 +1744,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 ());
@@ -1566,7 +1799,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 ();
@@ -1585,6 +1819,8 @@ namespace Mono.Data.Tds.Protocol
                                break;
                        }
 
+                       // VARADHAN: TDS 8 Debugging
+                       //Console.WriteLine ("In ProcessSubPacket... exit");
                        return subType;
                }
 
@@ -1596,7 +1832,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);
                                }
@@ -1608,6 +1844,11 @@ namespace Mono.Data.Tds.Protocol
                        }
                }
 
+               protected void SetCharset (Encoding encoder)
+               {
+                       comm.Encoder = encoder;
+               }
+               
                protected void SetCharset (string charset)
                {
                        if (charset == null || charset.Length > 30)
@@ -1624,7 +1865,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)
@@ -1640,9 +1881,22 @@ namespace Mono.Data.Tds.Protocol
                        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
                 #region asynchronous methods
                 protected IAsyncResult BeginExecuteQueryInternal (string sql, bool wantResults, 
                                                           AsyncCallback callback, object state)
@@ -1753,7 +2007,6 @@ namespace Mono.Data.Tds.Protocol
                 }
 
                 #endregion // asynchronous methods
-#endif // NET_2_0
 
 
        }