Duplex client has its own listener loop, so special care on reply is needed.
[mono.git] / mcs / class / System.Data / System.Data.SqlClient / SqlConnection.cs
index 38368e1d6e6d47d331989ff0e1bbfd4483bf5caf..ef5a4fc18b398c1719c69e779ff70f75779e9838 100644 (file)
@@ -45,14 +45,20 @@ using System.Collections.Specialized;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
+#if !MOBILE
 using System.EnterpriseServices;
+#endif
 using System.Globalization;
 using System.Net;
 using System.Net.Sockets;
 using System.Text;
 using System.Xml;
+#if NET_2_0
+using System.Collections.Generic;
+#endif
 
-namespace System.Data.SqlClient {
+namespace System.Data.SqlClient
+{
        [DefaultEvent ("InfoMessage")]
 #if NET_2_0
        public sealed class SqlConnection : DbConnection, IDbConnection, ICloneable
@@ -61,17 +67,22 @@ namespace System.Data.SqlClient {
 #endif // NET_2_0
        {
                #region Fields
+
                bool disposed;
 
                // The set of SQL connection pools
-               static TdsConnectionPoolManager sqlConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds70);
+               static TdsConnectionPoolManager sqlConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds80);
 #if NET_2_0
                const int DEFAULT_PACKETSIZE = 8000;
+               const int MAX_PACKETSIZE = 32768;
 #else
                const int DEFAULT_PACKETSIZE = 8192;
+               const int MAX_PACKETSIZE = 32767;
 #endif
+               const int MIN_PACKETSIZE = 512;
                const int DEFAULT_CONNECTIONTIMEOUT = 15;
                const int DEFAULT_MAXPOOLSIZE = 100;
+               const int MIN_MAXPOOLSIZE = 1;
                const int DEFAULT_MINPOOLSIZE = 0;
                const int DEFAULT_PORT = 1433;
 
@@ -86,8 +97,7 @@ namespace System.Data.SqlClient {
 
                // Connection parameters
                
-               TdsConnectionParameters parms = new TdsConnectionParameters ();
-               NameValueCollection connStringParameters;
+               TdsConnectionParameters parms;
                bool connectionReset;
                bool pooling;
                string dataSource;
@@ -98,7 +108,7 @@ namespace System.Data.SqlClient {
                int port;
                bool fireInfoMessageEventOnUserErrors;
                bool statisticsEnabled;
-
+               
                // The current state
                ConnectionState state = ConnectionState.Closed;
 
@@ -106,28 +116,18 @@ namespace System.Data.SqlClient {
                XmlReader xmlReader;
 
                // The TDS object
-               ITds tds;
+               Tds tds;
 
                #endregion // Fields
 
                #region Constructors
 
-               public SqlConnection () 
-                       : this (String.Empty)
+               public SqlConnection () : this (null)
                {
                }
        
                public SqlConnection (string connectionString)
                {
-                       Init (connectionString);
-               }
-
-               private void Init (string connectionString)
-               {
-                       connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
-                       dataSource = string.Empty;
-                       packetSize = DEFAULT_PACKETSIZE;
-                       port = DEFAULT_PORT;
                        ConnectionString = connectionString;
                }
 
@@ -142,7 +142,7 @@ namespace System.Data.SqlClient {
                [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
                [RecommendedAsConfigurable (true)]
                [RefreshProperties (RefreshProperties.All)]
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
@@ -156,7 +156,7 @@ namespace System.Data.SqlClient {
                        set {
                                if (state == ConnectionState.Open)
                                        throw new InvalidOperationException ("Not Allowed to change ConnectionString property while Connection state is OPEN");
-                               SetConnectionString (value); 
+                               SetConnectionString (value);
                        }
                }
        
@@ -164,7 +164,7 @@ namespace System.Data.SqlClient {
                [DataSysDescription ("Current connection timeout value, 'Connect Timeout=X' in the ConnectionString.")] 
 #endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
@@ -176,7 +176,7 @@ namespace System.Data.SqlClient {
                [DataSysDescription ("Current SQL Server database, 'Initial Catalog=X' in the connection string.")]
 #endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
@@ -199,7 +199,7 @@ namespace System.Data.SqlClient {
                [Browsable(true)]
 #endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
@@ -224,7 +224,7 @@ namespace System.Data.SqlClient {
                [DataSysDescription ("Version of the SQL Server accessed by the SqlConnection.")]
 #endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
@@ -242,7 +242,7 @@ namespace System.Data.SqlClient {
                [DataSysDescription ("The ConnectionState indicating whether the connection is open or closed.")]
 #endif
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
@@ -250,7 +250,7 @@ namespace System.Data.SqlClient {
                        get { return state; }
                }
 
-               internal ITds Tds {
+               internal Tds Tds {
                        get { return tds; }
                }
 
@@ -304,6 +304,15 @@ namespace System.Data.SqlClient {
 
                private void ErrorHandler (object sender, TdsInternalErrorMessageEventArgs e)
                {
+                       try {
+                               if (!tds.IsConnected)
+                                       Close ();
+                       } catch {
+                               try {
+                                       Close ();
+                               } catch {
+                               }
+                       }
                        throw new SqlException (e.Class, e.LineNumber, e.Message, e.Number, e.Procedure, e.Server, "Mono SqlClient Data Provider", e.State);
                }
 
@@ -316,20 +325,6 @@ namespace System.Data.SqlClient {
 
                #region Methods
 
-               internal string GetConnStringKeyValue (params string [] keys)
-               {
-                       if (connStringParameters == null || connStringParameters.Count == 0)
-                               return string.Empty;
-
-                       foreach (string key in keys) {
-                               string value = connStringParameters [key];
-                               if (value != null)
-                                       return value;
-                       }
-
-                       return string.Empty;
-               }
-
                public new SqlTransaction BeginTransaction ()
                {
                        return BeginTransaction (IsolationLevel.ReadCommitted, String.Empty);
@@ -399,11 +394,11 @@ namespace System.Data.SqlClient {
                        return transaction;
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-               void ChangeDatabase (string database) 
+               void ChangeDatabase (string database)
                {
                        if (!IsValidDatabaseName (database))
                                throw new ArgumentException (String.Format ("The database name {0} is not valid.", database));
@@ -414,16 +409,19 @@ namespace System.Data.SqlClient {
 
                private void ChangeState (ConnectionState currentState)
                {
+                       if (currentState == state)
+                               return;
+
                        ConnectionState originalState = state;
                        state = currentState;
                        OnStateChange (CreateStateChangeEvent (originalState, currentState));
                }
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-               void Close () 
+               void Close ()
                {
                        if (transaction != null && transaction.IsOpen)
                                transaction.Rollback ();
@@ -436,13 +434,13 @@ namespace System.Data.SqlClient {
 
                        if (tds != null && tds.IsConnected) {
                                if (pooling && tds.Pooling) {
-#if NET_2_0
-                                       if(pool != null) pool.ReleaseConnection (ref tds);
-#else
-                                       if(pool != null) pool.ReleaseConnection (tds);
-#endif
-                               }else
-                                       if(tds != null) tds.Disconnect ();
+                                       if (pool != null) {
+                                               pool.ReleaseConnection (tds);
+                                               pool = null;
+                                       }
+                               } else {
+                                       tds.Disconnect ();
+                               }
                        }
 
                        if (tds != null) {
@@ -453,7 +451,7 @@ namespace System.Data.SqlClient {
                        ChangeState (ConnectionState.Closed);
                }
 
-               public new SqlCommand CreateCommand () 
+               public new SqlCommand CreateCommand ()
                {
                        SqlCommand command = new SqlCommand ();
                        command.Connection = this;
@@ -470,17 +468,13 @@ namespace System.Data.SqlClient {
                        return new StateChangeEventArgs (originalState, currentState);
                }
 
-               protected override void Dispose (bool disposing) 
+               protected override void Dispose (bool disposing)
                {
-                       if (disposed)
-                               return;
-
                        try {
-                               if (disposing) {
+                               if (disposing && !disposed) {
                                        if (State == ConnectionState.Open) 
                                                Close ();
-                                       ConnectionString = string.Empty;
-                                       SetDefaultConnectionParameters (this.connStringParameters); 
+                                       ConnectionString = null;
                                }
                        } finally {
                                disposed = true;
@@ -488,11 +482,13 @@ namespace System.Data.SqlClient {
                        }
                }
 
+#if !MOBILE
                [MonoTODO ("Not sure what this means at present.")]
                public void EnlistDistributedTransaction (ITransaction transaction)
                {
                        throw new NotImplementedException ();
                }
+#endif
 
                object ICloneable.Clone ()
                {
@@ -500,9 +496,9 @@ namespace System.Data.SqlClient {
                }
 
 #if NET_2_0
-               protected override DbTransaction BeginDbTransaction (IsolationLevel level)
+               protected override DbTransaction BeginDbTransaction (IsolationLevel isolationLevel)
                {
-                       return (DbTransaction)BeginTransaction (level);
+                       return BeginTransaction (isolationLevel);
                }
 
                protected override DbCommand CreateDbCommand ()
@@ -526,11 +522,11 @@ namespace System.Data.SqlClient {
                }
 #endif
 
-               public 
+               public
 #if NET_2_0
                override
 #endif // NET_2_0
-               void Open () 
+               void Open ()
                {
                        string serverName = string.Empty;
                        if (state == ConnectionState.Open)
@@ -543,7 +539,8 @@ namespace System.Data.SqlClient {
                                if (!pooling) {
                                        if(!ParseDataSource (dataSource, out port, out serverName))
                                                throw new SqlException(20, 0, "SQL Server does not exist or access denied.",  17, "ConnectionOpen (Connect()).", dataSource, parms.ApplicationName, 0);
-                                       tds = new Tds70 (serverName, port, PacketSize, ConnectionTimeout);
+                                       tds = new Tds80 (serverName, port, PacketSize, ConnectionTimeout);
+                                       tds.Pooling = false;
                                }
                                else {
                                        if(!ParseDataSource (dataSource, out port, out serverName))
@@ -570,15 +567,13 @@ namespace System.Data.SqlClient {
                                                pool.ReleaseConnection (tds);
                                        throw;
                                }
-                       } else if (connectionReset) {
-                               tds.Reset ();
                        }
 
                        disposed = false; // reset this, so using () would call Close ().
                        ChangeState (ConnectionState.Open);
                }
 
-               private bool ParseDataSource (string theDataSource, out int thePort, out string theServerName) 
+               private bool ParseDataSource (string theDataSource, out int thePort, out string theServerName)
                {
                        theServerName = string.Empty;
                        string theInstanceName = string.Empty;
@@ -590,22 +585,24 @@ namespace System.Data.SqlClient {
                        bool success = true;
 
                        int idx = 0;
-                       if ((idx = theDataSource.IndexOf (",")) > -1) {
+                       if ((idx = theDataSource.IndexOf (',')) > -1) {
                                theServerName = theDataSource.Substring (0, idx);
                                string p = theDataSource.Substring (idx + 1);
                                thePort = Int32.Parse (p);
-                       } else if ((idx = theDataSource.IndexOf ("\\")) > -1) {
+                       } else if ((idx = theDataSource.IndexOf ('\\')) > -1) {
                                theServerName = theDataSource.Substring (0, idx);
                                theInstanceName = theDataSource.Substring (idx + 1);
+
                                // do port discovery via UDP port 1434
                                port = DiscoverTcpPortViaSqlMonitor (theServerName, theInstanceName);
                                if (port == -1)
                                        success = false;
-                       } else if (theDataSource.Length == 0 || theDataSource == "(local)")
-                               theServerName = "localhost";
-                       else
+                       } else
                                theServerName = theDataSource;
 
+                       if (theServerName.Length == 0 || theServerName == "(local)" || theServerName == ".")
+                               theServerName = "localhost";
+
                        if ((idx = theServerName.IndexOf ("tcp:")) > -1)
                                theServerName = theServerName.Substring (idx + 4);
 
@@ -617,11 +614,14 @@ namespace System.Data.SqlClient {
                        if (value.ToUpper() == "SSPI")
                                return true;
 
-                       return ConvertToBoolean("integrated security", value);
+                       return ConvertToBoolean ("integrated security", value, false);
                }
 
-               private bool ConvertToBoolean (string key, string value)
+               private bool ConvertToBoolean (string key, string value, bool defaultValue)
                {
+                       if (value.Length == 0)
+                               return defaultValue;
+
                        string upperValue = value.ToUpper ();
 
                        if (upperValue == "TRUE" || upperValue == "YES")
@@ -633,13 +633,16 @@ namespace System.Data.SqlClient {
                                "Invalid value \"{0}\" for key '{1}'.", value, key));
                }
 
-               private int ConvertToInt32 (string key, string value)
+               private int ConvertToInt32 (string key, string value, int defaultValue)
                {
+                       if (value.Length == 0)
+                               return defaultValue;
+
                        try {
                                return int.Parse (value);
                        } catch (Exception ex) {
                                throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
-                                       "Invalid value \"{0}\" for key '{1}'.", value, key));
+                                       "Invalid value \"{0}\" for key '{1}'.", value, key), ex);
                        }
                }
 
@@ -654,12 +657,10 @@ namespace System.Data.SqlClient {
        
                void SetConnectionString (string connectionString)
                {
-                       NameValueCollection parameters = new NameValueCollection ();
-                       SetDefaultConnectionParameters (parameters);
+                       SetDefaultConnectionParameters ();
 
                        if ((connectionString == null) || (connectionString.Trim().Length == 0)) {
                                this.connectionString = connectionString;
-                               this.connStringParameters = parameters;
                                return;
                        }
 
@@ -708,8 +709,7 @@ namespace System.Data.SqlClient {
                                        else {
                                                if (name != String.Empty && name != null) {
                                                        value = sb.ToString ();
-                                                       SetProperties (name.ToUpper ().Trim() , value);
-                                                       parameters [name.ToUpper ().Trim ()] = value.Trim ();
+                                                       SetProperties (name.ToLower ().Trim() , value);
                                                }
                                                else if (sb.Length != 0)
                                                        throw new ArgumentException ("Format of initialization string does not conform to specifications");
@@ -745,14 +745,22 @@ namespace System.Data.SqlClient {
                                }
                        }
 
+                       if (minPoolSize > maxPoolSize)
+                               throw new ArgumentException ("Invalid value for "
+                                       + "'min pool size' or 'max pool size'; "
+                                       + "'min pool size' must not be greater "
+                                       + "than 'max pool size'.");
+
                        connectionString = connectionString.Substring (0 , connectionString.Length-1);
                        this.connectionString = connectionString;
-                       this.connStringParameters = parameters;
                }
 
-               void SetDefaultConnectionParameters (NameValueCollection parameters)
+               void SetDefaultConnectionParameters ()
                {
-                       parms.Reset ();
+                       if (parms == null)
+                               parms = new TdsConnectionParameters ();
+                       else
+                               parms.Reset ();
                        dataSource = string.Empty;
                        connectionTimeout = DEFAULT_CONNECTIONTIMEOUT;
                        connectionReset = true;
@@ -760,142 +768,139 @@ namespace System.Data.SqlClient {
                        maxPoolSize = DEFAULT_MAXPOOLSIZE;
                        minPoolSize = DEFAULT_MINPOOLSIZE;
                        packetSize = DEFAULT_PACKETSIZE;
-                       
-                       parameters["APPLICATION NAME"] = "Mono SqlClient Data Provider";
-                       parameters["CONNECT TIMEOUT"] = connectionTimeout.ToString (CultureInfo.InvariantCulture);
-                       parameters["CONNECTION LIFETIME"] = "0";
-                       parameters["CONNECTION RESET"] = "true";
-                       parameters["ENLIST"] = "true";
-                       parameters["INTEGRATED SECURITY"] = "false";
-                       parameters["INITIAL CATALOG"] = string.Empty;
-                       parameters["MAX POOL SIZE"] = maxPoolSize.ToString (CultureInfo.InvariantCulture);
-                       parameters["MIN POOL SIZE"] = minPoolSize.ToString (CultureInfo.InvariantCulture);
-                       parameters["NETWORK LIBRARY"] = "dbmssocn";
-                       parameters["PACKET SIZE"] = packetSize.ToString (CultureInfo.InvariantCulture);
-                       parameters["PERSIST SECURITY INFO"] = "false";
-                       parameters["POOLING"] = "true";
-                       parameters["WORKSTATION ID"] = Environment.MachineName;
+                       port = DEFAULT_PORT;
  #if NET_2_0
                        async = false;
-                       parameters ["ASYNCHRONOUS PROCESSING"] = "false";
  #endif
                }
-               
+
                private void SetProperties (string name , string value)
                {
                        switch (name) {
-                       case "APP" :
-                       case "APPLICATION NAME" :
+                       case "app" :
+                       case "application name" :
                                parms.ApplicationName = value;
                                break;
-                       case "ATTACHDBFILENAME" :
-                       case "EXTENDED PROPERTIES" :
-                       case "INITIAL FILE NAME" :
+                       case "attachdbfilename" :
+                       case "extended properties" :
+                       case "initial file name" :
                                parms.AttachDBFileName = value;
                                break;
-                       case "TIMEOUT" :
-                       case "CONNECT TIMEOUT" :
-                       case "CONNECTION TIMEOUT" :
-                               int tmpTimeout = ConvertToInt32 ("connection timeout", value);
+                       case "timeout" :
+                       case "connect timeout" :
+                       case "connection timeout" :
+                               int tmpTimeout = ConvertToInt32 ("connect timeout", value,
+                                       DEFAULT_CONNECTIONTIMEOUT);
                                if (tmpTimeout < 0)
-                                       throw new ArgumentException ("Invalid CONNECTION TIMEOUT .. Must be an integer >=0 ");
+                                       throw new ArgumentException ("Invalid 'connect timeout'. Must be an integer >=0 ");
                                else 
                                        connectionTimeout = tmpTimeout;
                                break;
-                       case "CONNECTION LIFETIME" :
+                       case "connection lifetime" :
                                break;
-                       case "CONNECTION RESET" :
-                               connectionReset = ConvertToBoolean ("connection reset", value);
+                       case "connection reset" :
+                               connectionReset = ConvertToBoolean ("connection reset", value, true);
                                break;
-                       case "LANGUAGE" :
-                       case "CURRENT LANGUAGE" :
+                       case "language" :
+                       case "current language" :
                                parms.Language = value;
                                break;
-                       case "DATA SOURCE" :
-                       case "SERVER" :
-                       case "ADDRESS" :
-                       case "ADDR" :
-                       case "NETWORK ADDRESS" :
+                       case "data source" :
+                       case "server" :
+                       case "address" :
+                       case "addr" :
+                       case "network address" :
                                dataSource = value;
                                break;
-                       case "ENCRYPT":
-                               if (ConvertToBoolean("encrypt", value))
+                       case "encrypt":
+                               if (ConvertToBoolean (name, value, false))
                                        throw new NotImplementedException("SSL encryption for"
                                                + " data sent between client and server is not"
                                                + " implemented.");
                                break;
-                       case "ENLIST" :
-                               if (!ConvertToBoolean("enlist", value))
+                       case "enlist" :
+                               if (!ConvertToBoolean (name, value, true))
                                        throw new NotImplementedException("Disabling the automatic"
                                                + " enlistment of connections in the thread's current"
                                                + " transaction context is not implemented.");
                                break;
-                       case "INITIAL CATALOG" :
-                       case "DATABASE" :
+                       case "initial catalog" :
+                       case "database" :
                                parms.Database = value;
                                break;
-                       case "INTEGRATED SECURITY" :
-                       case "TRUSTED_CONNECTION" :
+                       case "integrated security" :
+                       case "trusted_connection" :
                                parms.DomainLogin = ConvertIntegratedSecurity(value);
                                break;
-                       case "MAX POOL SIZE" :
-                               int tmpMaxPoolSize = ConvertToInt32 ("max pool size" , value);
-                               if (tmpMaxPoolSize < 0)
-                                       throw new ArgumentException ("Invalid MAX POOL SIZE. Must be a intger >= 0");
+                       case "max pool size" :
+                               int tmpMaxPoolSize = ConvertToInt32 (name, value, DEFAULT_MAXPOOLSIZE);
+                               if (tmpMaxPoolSize < MIN_MAXPOOLSIZE)
+                                       throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+                                               "Invalid '{0}'. The value must be greater than {1}.",
+                                               name, MIN_MAXPOOLSIZE));
                                else
                                        maxPoolSize = tmpMaxPoolSize;
                                break;
-                       case "MIN POOL SIZE" :
-                               int tmpMinPoolSize = ConvertToInt32 ("min pool size" , value);
+                       case "min pool size" :
+                               int tmpMinPoolSize = ConvertToInt32 (name, value, DEFAULT_MINPOOLSIZE);
                                if (tmpMinPoolSize < 0)
-                                       throw new ArgumentException ("Invalid MIN POOL SIZE. Must be a intger >= 0");
+                                       throw new ArgumentException ("Invalid 'min pool size'. Must be a integer >= 0");
                                else
                                        minPoolSize = tmpMinPoolSize;
                                break;
-#if NET_2_0    
-                       case "MULTIPLEACTIVERESULTSETS":
+#if NET_2_0
+                       case "multipleactiveresultsets":
+                               // FIXME: not implemented
+                               ConvertToBoolean (name, value, false);
                                break;
-                       case "ASYNCHRONOUS PROCESSING" :
-                       case "ASYNC" :
-                               async = ConvertToBoolean (name, value);
+                       case "asynchronous processing" :
+                       case "async" :
+                               async = ConvertToBoolean (name, value, false);
                                break;
-#endif 
-                       case "NET" :
-                       case "NETWORK" :
-                       case "NETWORK LIBRARY" :
+#endif
+                       case "net" :
+                       case "network" :
+                       case "network library" :
                                if (!value.ToUpper ().Equals ("DBMSSOCN"))
                                        throw new ArgumentException ("Unsupported network library.");
                                break;
-                       case "PACKET SIZE" :
-                               int tmpPacketSize = ConvertToInt32 ("packet size", value);
-                               if (tmpPacketSize < 512 || tmpPacketSize > 32767)
-                                       throw new ArgumentException ("Invalid PACKET SIZE. The integer must be between 512 and 32767");
+                       case "packet size" :
+                               int tmpPacketSize = ConvertToInt32 (name, value, DEFAULT_PACKETSIZE);
+                               if (tmpPacketSize < MIN_PACKETSIZE || tmpPacketSize > MAX_PACKETSIZE)
+                                       throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
+                                               "Invalid 'Packet Size'. The value must be between {0} and {1}.",
+                                               MIN_PACKETSIZE, MAX_PACKETSIZE));
                                else
                                        packetSize = tmpPacketSize;
                                break;
-                       case "PASSWORD" :
-                       case "PWD" :
+                       case "password" :
+                       case "pwd" :
                                parms.Password = value;
                                break;
-                       case "PERSISTSECURITYINFO" :
-                       case "PERSIST SECURITY INFO" :
+                       case "persistsecurityinfo" :
+                       case "persist security info" :
                                // FIXME : not implemented
                                // throw new NotImplementedException ();
                                break;
-                       case "POOLING" :
-                               pooling = ConvertToBoolean("pooling", value);
+                       case "pooling" :
+                               pooling = ConvertToBoolean (name, value, true);
                                break;
-                       case "UID" :
-                       case "USER" :
-                       case "USER ID" :
+                       case "uid" :
+                       case "user" :
+                       case "user id" :
                                parms.User = value;
                                break;
-                       case "WSID" :
-                       case "WORKSTATION ID" :
+                       case "wsid" :
+                       case "workstation id" :
                                parms.Hostname = value;
                                break;
+#if NET_2_0
+                       case "user instance":
+                               userInstance = ConvertToBoolean (name, value, false);
+                               break;
+#endif
                        default :
-                               throw new ArgumentException("Keyword not supported :"+name);
+                               throw new ArgumentException("Keyword not supported : '" + name + "'.");
                        }
                }
 
@@ -932,7 +937,7 @@ namespace System.Data.SqlClient {
                }
 #endif
 
-               private sealed class SqlMonitorSocket : UdpClient 
+               private sealed class SqlMonitorSocket : UdpClient
                {
                        // UDP port that the SQL Monitor listens
                        private static readonly int SqlMonitorUdpPort = 1434;
@@ -948,7 +953,7 @@ namespace System.Data.SqlClient {
                                instance = InstanceName;
                        }
 
-                       internal int DiscoverTcpPort (int timeoutSeconds) 
+                       internal int DiscoverTcpPort (int timeoutSeconds)
                        {
                                int SqlServerTcpPort;
                                Client.Blocking = false;
@@ -958,7 +963,7 @@ namespace System.Data.SqlClient {
                                Byte[] rawrq = new Byte [instance.Length + 1];
                                rawrq[0] = 4;
                                enc.GetBytes (instance, 0, instance.Length, rawrq, 1);
-                               int bytes = Send (rawrq, rawrq.Length);
+                               Send (rawrq, rawrq.Length);
 
                                if (!Active)
                                        return -1; // Error
@@ -987,8 +992,13 @@ namespace System.Data.SqlClient {
                                for (int i = 0; i < rawtokens.Length / 2 && i < 256; i++) {
                                        data [rawtokens [i * 2]] = rawtokens [ i * 2 + 1];
                                }
-                               if (!data.ContainsKey ("tcp")) 
-                                       throw new NotImplementedException ("Only TCP/IP is supported.");
+
+                               if (!data.ContainsKey ("tcp")) {
+                                       string msg = "Mono does not support names pipes or shared memory "
+                                               + "for connecting to SQL Server. Please enable the TCP/IP "
+                                               + "protocol.";
+                                       throw new NotImplementedException (msg);
+                               }
 
                                SqlServerTcpPort = int.Parse ((string) data ["tcp"]);
                                Close ();
@@ -998,9 +1008,11 @@ namespace System.Data.SqlClient {
                }
 
 #if NET_2_0
-               struct ColumnInfo {
+               struct ColumnInfo
+               {
                        public string name;
                        public Type type;
+
                        public ColumnInfo (string name, Type type)
                        {
                                this.name = name; this.type = type;
@@ -1672,10 +1684,12 @@ namespace System.Data.SqlClient {
                
                public static void ChangePassword (string connectionString, string newPassword)
                {
-                       if (connectionString == null || newPassword == null || newPassword == String.Empty)
-                               throw new ArgumentNullException ();
+                       if (String.IsNullOrEmpty (connectionString))
+                               throw new ArgumentNullException ("The 'connectionString' cannot be null or empty.");
+                       if (String.IsNullOrEmpty (newPassword))
+                               throw new ArgumentNullException ("The 'newPassword' cannot be null or empty.");
                        if (newPassword.Length > 128)
-                               throw new ArgumentException ("The value of newPassword exceeds its permittable length which is 128");
+                               throw new ArgumentException ("The length of 'newPassword' cannot exceed 128 characters.");
                        using (SqlConnection conn = new SqlConnection (connectionString)) {
                                conn.Open ();
                                conn.tds.Execute (String.Format ("sp_password '{0}', '{1}', '{2}'",
@@ -1685,22 +1699,25 @@ namespace System.Data.SqlClient {
 
                public static void ClearAllPools ()
                {
-                       Hashtable pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
+                       // FIXME: locking
+                       IDictionary pools = SqlConnection.sqlConnectionPools.GetConnectionPool ();
                        foreach (TdsConnectionPool pool in pools.Values) {
-                               if (pool != null) {
+                               if (pool != null)
                                        pool.ResetConnectionPool ();
-                                       ITds tds = pool.GetConnection ();
-                                       tds.Pooling = false;
-                               }
                        }
+                       pools.Clear ();
                }
 
                public static void ClearPool (SqlConnection connection)
                {
+                       if (connection == null)
+                               throw new ArgumentNullException ("connection");
+
+                       // FIXME: locking
                        if (connection.pooling) {
-                               connection.pooling = false;
-                               if (connection.pool != null)
-                                       connection.pool.ResetConnectionPool (connection.Tds);
+                               TdsConnectionPool pool = sqlConnectionPools.GetConnectionPool (connection.ConnectionString);
+                               if (pool != null)
+                                       pool.ResetConnectionPool ();
                        }
                }
 
@@ -1711,7 +1728,8 @@ namespace System.Data.SqlClient {
 #if NET_2_0
                #region Fields Net 2
 
-               bool async = false;
+               bool async;
+               bool userInstance;
 
                #endregion // Fields  Net 2