X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Data%2FSystem.Data.SqlClient%2FSqlConnection.cs;h=ef5a4fc18b398c1719c69e779ff70f75779e9838;hb=cb091188403237aa3eb87f39a09f00f642750cc2;hp=77167740b912b24e9fe83d255ed4506cf779cab1;hpb=3aeddf81e9bb63e3e68c593e6530ee5f744721b4;p=mono.git diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs index 77167740b91..ef5a4fc18b3 100644 --- a/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs +++ b/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs @@ -45,12 +45,17 @@ 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 { @@ -66,14 +71,18 @@ namespace System.Data.SqlClient 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; @@ -88,8 +97,7 @@ namespace System.Data.SqlClient // Connection parameters - TdsConnectionParameters parms = new TdsConnectionParameters (); - NameValueCollection connStringParameters; + TdsConnectionParameters parms; bool connectionReset; bool pooling; string dataSource; @@ -100,7 +108,7 @@ namespace System.Data.SqlClient int port; bool fireInfoMessageEventOnUserErrors; bool statisticsEnabled; - + // The current state ConnectionState state = ConnectionState.Closed; @@ -108,27 +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; } @@ -157,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); } } @@ -251,7 +250,7 @@ namespace System.Data.SqlClient get { return state; } } - internal ITds Tds { + internal Tds Tds { get { return tds; } } @@ -305,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); } @@ -317,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); @@ -404,7 +398,7 @@ namespace System.Data.SqlClient #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)); @@ -415,6 +409,9 @@ namespace System.Data.SqlClient private void ChangeState (ConnectionState currentState) { + if (currentState == state) + return; + ConnectionState originalState = state; state = currentState; OnStateChange (CreateStateChangeEvent (originalState, currentState)); @@ -424,7 +421,7 @@ namespace System.Data.SqlClient #if NET_2_0 override #endif // NET_2_0 - void Close () + void Close () { if (transaction != null && transaction.IsOpen) transaction.Rollback (); @@ -437,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) { @@ -454,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; @@ -473,15 +470,11 @@ namespace System.Data.SqlClient 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; @@ -489,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 () { @@ -544,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)) @@ -571,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; @@ -591,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); @@ -618,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") @@ -634,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); } } @@ -655,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; } @@ -709,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"); @@ -746,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; @@ -761,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 + "'."); } } @@ -933,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; @@ -949,7 +953,7 @@ namespace System.Data.SqlClient instance = InstanceName; } - internal int DiscoverTcpPort (int timeoutSeconds) + internal int DiscoverTcpPort (int timeoutSeconds) { int SqlServerTcpPort; Client.Blocking = false; @@ -959,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 @@ -988,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 (); @@ -999,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; @@ -1673,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}'", @@ -1686,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 (); } } @@ -1712,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