New test.
[mono.git] / mcs / class / Mono.Data.SybaseClient / Mono.Data.SybaseClient / SybaseConnection.cs
index 20bba7c25c4b27f190c697b728e9b58c09d5917e..23a8c9cb2172bd4f935b504fb2c8eaba6ad0d870 100644 (file)
@@ -3,8 +3,31 @@
 //
 // Author:
 //   Tim Coleman (tim@timcoleman.com)
+//   Daniel Morgan (danmorg@sc.rr.com)
 //
-// Copyright (C) Tim Coleman, 2002
+// Copyright (C) Tim Coleman, 2002-2003
+// Copyright (C) Daniel Morgan, 2003
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
 using Mono.Data.Tds.Protocol;
@@ -16,6 +39,7 @@ using System.Data;
 using System.Data.Common;
 using System.EnterpriseServices;
 using System.Net;
+using System.Net.Sockets;
 using System.Text;
 
 namespace Mono.Data.SybaseClient {
@@ -25,10 +49,10 @@ namespace Mono.Data.SybaseClient {
                bool disposed = false;
 
                // The set of SQL connection pools
-               static Hashtable SybaseConnectionPools = new Hashtable ();
+               static TdsConnectionPoolManager sybaseConnectionPools = new TdsConnectionPoolManager (TdsVersion.tds50);
 
                // The current connection pool
-               SybaseConnectionPool pool;
+               TdsConnectionPool pool;
 
                // The connection string that identifies this connection
                string connectionString = null;
@@ -45,7 +69,7 @@ namespace Mono.Data.SybaseClient {
                int minPoolSize;
                int maxPoolSize;
                int packetSize;
-               int port = 1533;
+               int port = 2048;
 
                // The current state
                ConnectionState state = ConnectionState.Closed;
@@ -182,7 +206,7 @@ namespace Mono.Data.SybaseClient {
                                break;
                        }
 
-                       tds.ExecuteNonQuery (String.Format ("SET TRANSACTION ISOLATION LEVEL {0};BEGIN TRANSACTION {1}", isolevel, transactionName));
+                       tds.Execute (String.Format ("SET TRANSACTION ISOLATION LEVEL {0}\nBEGIN TRANSACTION {1}", isolevel, transactionName));
                        transaction = new SybaseTransaction (this, iso);
                        return transaction;
                }
@@ -193,7 +217,7 @@ namespace Mono.Data.SybaseClient {
                                throw new ArgumentException (String.Format ("The database name {0} is not valid."));
                        if (State != ConnectionState.Open)
                                throw new InvalidOperationException ("The connection is not open");
-                       tds.ExecuteNonQuery (String.Format ("use {0}", database));
+                       tds.Execute (String.Format ("use {0}", database));
                }
 
                private void ChangeState (ConnectionState currentState)
@@ -282,19 +306,20 @@ namespace Mono.Data.SybaseClient {
                [MonoTODO ("Figure out the Sybase way to reset the connection.")]
                public void Open () 
                {
-                       if (connectionString == null)
+                       string serverName = "";
+                       if (connectionString == null || connectionString.Equals (""))
                                throw new InvalidOperationException ("Connection string has not been initialized.");
 
                        try {
-                               if (!pooling)
-                                       tds = new Tds50 (DataSource, port, PacketSize, ConnectionTimeout);
+                               if (!pooling) {
+                                       ParseDataSource (dataSource, out port, out serverName);
+                                       tds = new Tds50 (serverName, port, PacketSize, ConnectionTimeout);
+                               }
                                else {
-                                       pool = (SybaseConnectionPool) SybaseConnectionPools [connectionString];
-                                       if (pool == null) {
-                                               pool = new SybaseConnectionPool (dataSource, port, packetSize, ConnectionTimeout, minPoolSize, maxPoolSize);
-                                               SybaseConnectionPools [connectionString] = pool;
-                                       }
-                                       tds = pool.AllocateConnection ();
+                                       ParseDataSource (dataSource, out port, out serverName);
+                                       TdsConnectionInfo info = new TdsConnectionInfo (serverName, port, packetSize, ConnectionTimeout, minPoolSize, maxPoolSize);
+                                       pool = sybaseConnectionPools.GetConnectionPool (connectionString, info);
+                                       tds = pool.GetConnection ();
                                }
                        }
                        catch (TdsTimeoutException e) {
@@ -305,9 +330,16 @@ namespace Mono.Data.SybaseClient {
                        tds.TdsInfoMessage += new TdsInternalInfoMessageEventHandler (MessageHandler);
 
                        if (!tds.IsConnected) {
-                               tds.Connect (parms);
-                               ChangeState (ConnectionState.Open);
-                               ChangeDatabase (parms.Database);
+                               try {
+                                       tds.Connect (parms);
+                                       ChangeState (ConnectionState.Open);
+                                       ChangeDatabase (parms.Database);
+                               }
+                               catch {
+                                       if (pooling)
+                                               pool.ReleaseConnection (tds);
+                                       throw;
+                               }
                        }
                        else if (connectionReset) {
                                // tds.ExecuteNonQuery ("EXEC sp_reset_connection"); FIXME
@@ -315,174 +347,209 @@ namespace Mono.Data.SybaseClient {
                        }
                }
 
-                void SetConnectionString (string connectionString)
-                {
-                        connectionString += ";";
-                        NameValueCollection parameters = new NameValueCollection ();
-
-                        if (connectionString == String.Empty)
-                                return;
-
-                        bool inQuote = false;
-                        bool inDQuote = false;
-
-                        string name = String.Empty;
-                        string value = String.Empty;
-                        StringBuilder sb = new StringBuilder ();
-
-                        foreach (char c in connectionString)
-                        {
-                                switch (c) {
-                                case '\'':
-                                        inQuote = !inQuote;
-                                        break;
-                                case '"' :
-                                        inDQuote = !inDQuote;
-                                        break;
-                                case ';' :
-                                        if (!inDQuote && !inQuote) {
-                                               if (name != String.Empty && name != null) {
-                                                       value = sb.ToString ();
-                                                       parameters [name.ToUpper ().Trim ()] = value.Trim ();
-                                               }
-                                                name = String.Empty;
-                                                value = String.Empty;
-                                                sb = new StringBuilder ();
-                                        }
-                                        else
-                                                sb.Append (c);
-                                        break;
-                                case '=' :
-                                        if (!inDQuote && !inQuote) {
-                                                name = sb.ToString ();
-                                                sb = new StringBuilder ();
-                                        }
-                                        else
-                                                sb.Append (c);
-                                        break;
-                                default:
-                                        sb.Append (c);
-                                        break;
-                                }
-                        }
-
-                        if (this.ConnectionString == null)
-                        {
-                                SetDefaultConnectionParameters (parameters);
-                        }
-
-                        SetProperties (parameters);
-
-                        this.connectionString = connectionString;
-                }
-
-                void SetDefaultConnectionParameters (NameValueCollection parameters)
-                {
-                        if (null == parameters.Get ("APPLICATION NAME"))
-                                parameters["APPLICATION NAME"] = ".Net SybaseClient Data Provider";
-                        if (null == parameters.Get ("CONNECT TIMEOUT") && null == parameters.Get ("CONNECTION TIMEOUT"))
-                                parameters["CONNECT TIMEOUT"] = "15";
-                        if (null == parameters.Get ("CONNECTION LIFETIME"))
-                                parameters["CONNECTION LIFETIME"] = "0";
-                        if (null == parameters.Get ("CONNECTION RESET"))
-                                parameters["CONNECTION RESET"] = "true";
-                        if (null == parameters.Get ("ENLIST"))
-                                parameters["ENLIST"] = "true";
-                        if (null == parameters.Get ("INTEGRATED SECURITY") && null == parameters.Get ("TRUSTED_CONNECTION"))
-                                parameters["INTEGRATED SECURITY"] = "false";
-                        if (null == parameters.Get ("MAX POOL SIZE"))
-                                parameters["MAX POOL SIZE"] = "100";
-                        if (null == parameters.Get ("MIN POOL SIZE"))
-                                parameters["MIN POOL SIZE"] = "0";
-                        if (null == parameters.Get ("NETWORK LIBRARY") && null == parameters.Get ("NET"))
-                                parameters["NETWORK LIBRARY"] = "dbmssocn";
-                        if (null == parameters.Get ("PACKET SIZE"))
-                                parameters["PACKET SIZE"] = "512";
-                        if (null == parameters.Get ("PERSIST SECURITY INFO"))
-                                parameters["PERSIST SECURITY INFO"] = "false";
-                        if (null == parameters.Get ("POOLING"))
-                                parameters["POOLING"] = "true";
-                        if (null == parameters.Get ("WORKSTATION ID"))
-                                parameters["WORKSTATION ID"] = Dns.GetHostByName ("localhost").HostName;
-                }
-
-                private void SetProperties (NameValueCollection parameters)
-                {
-                        string value;
-                        foreach (string name in parameters) {
-                                value = parameters[name];
-
-                                switch (name) {
-                                case "APPLICATION NAME" :
-                                        parms.ApplicationName = value;
-                                        break;
-                                case "ATTACHDBFILENAME" :
-                                case "EXTENDED PROPERTIES" :
-                                case "INITIAL FILE NAME" :
-                                        break;
-                                case "CONNECT TIMEOUT" :
-                                case "CONNECTION TIMEOUT" :
-                                        connectionTimeout = Int32.Parse (value);
-                                        break;
-                                case "CONNECTION LIFETIME" :
-                                        break;
-                                case "CONNECTION RESET" :
-                                        connectionReset = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
-                                        break;
-                                case "CURRENT LANGUAGE" :
-                                        parms.Language = value;
-                                        break;
-                                case "DATA SOURCE" :
-                                case "SERVER" :
-                                case "ADDRESS" :
-                                case "ADDR" :
-                                case "NETWORK ADDRESS" :
-                                        dataSource = value;
-                                        break;
-                                case "ENLIST" :
-                                        break;
-                                case "INITIAL CATALOG" :
-                                case "DATABASE" :
-                                        parms.Database = value;
-                                        break;
-                                case "INTEGRATED SECURITY" :
-                                case "TRUSTED_CONNECTION" :
-                                        break;
-                                case "MAX POOL SIZE" :
-                                        maxPoolSize = Int32.Parse (value);
-                                        break;
-                                case "MIN POOL SIZE" :
-                                        minPoolSize = Int32.Parse (value);
-                                        break;
-                                case "NET" :
-                                case "NETWORK LIBRARY" :
-                                        if (!value.ToUpper ().Equals ("DBMSSOCN"))
-                                                throw new ArgumentException ("Unsupported network library.");
-                                        break;
-                                case "PACKET SIZE" :
-                                        packetSize = Int32.Parse (value);
-                                        break;
-                                case "PASSWORD" :
-                                case "PWD" :
-                                        parms.Password = value;
-                                        break;
-                                case "PERSIST SECURITY INFO" :
-                                        break;
-                                case "POOLING" :
-                                        pooling = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
-                                        break;
-                                case "USER ID" :
-                                        parms.User = value;
-                                        break;
-                                case "WORKSTATION ID" :
-                                        parms.Hostname = value;
-                                        break;
-                                }
+               private void ParseDataSource (string theDataSource, out int thePort, out string theServerName) 
+               {
+                       theServerName = "";
+                       thePort = 2048; 
+                                               
+                       int idx = 0;
+                       if ((idx = theDataSource.IndexOf (",")) > -1) {
+                               theServerName = theDataSource.Substring (0, idx);
+                               string p = theDataSource.Substring (idx + 1);
+                               thePort = Int32.Parse (p);
+                       }
+                       else {
+                               theServerName = theDataSource;
+                       }
+               }
+
+               private string ParseValue (string name, string value)
+               {
+                       if (name.Length == 0 && value.Length > 0)
+                               throw new ArgumentException ("Expected '=' delimiter while parsing connection value pair.");
+                       if (name.Length > 0)
+                               return value.Trim ();
+                       return String.Empty;
+               }
+
+               private void SetConnectionString (string connectionString)
+               {
+                       if (connectionString == String.Empty) {
+                               this.connectionString = connectionString;
+                               return;
+                       }
+
+                       NameValueCollection parameters = new NameValueCollection ();
+
+                       string name = String.Empty;
+                       string value = String.Empty;
+                       StringBuilder sb = new StringBuilder ();
+
+                       char delimiter = '\0';
+
+                       foreach (char c in connectionString) {
+                               switch (c) {
+                               case '\'' :
+                               case '"' :
+                                       if (delimiter.Equals (c))
+                                               delimiter = '\0';
+                                       else if (delimiter.Equals ('\0'))
+                                               delimiter = c;
+                                       else
+                                               sb.Append (c);
+                                       break;
+                               case ';' :
+                                       if (delimiter.Equals ('\0')) {
+                                               value = ParseValue (name, sb.ToString ());
+                                               if (!value.Equals ("")) 
+                                                       parameters [name.ToUpper ().Trim ()] = value;
+                                               name = String.Empty;
+                                               sb = new StringBuilder ();
+                                       } 
+                                       else
+                                               sb.Append (c);
+                                       break;
+                               case '=' :
+                                       if (delimiter.Equals ('\0')) {
+                                               name = sb.ToString ();
+                                               sb = new StringBuilder ();
+                                       }
+                                       else
+                                               sb.Append (c);
+                                       break;
+                               default:
+                                       sb.Append (c);
+                                       break;
+                               }
+                       }
+
+                       if (!delimiter.Equals ('\0'))
+                               throw new ArgumentException (String.Format ("Matching end delimiter {0} not found in connection option value.", delimiter));
+
+                       value = ParseValue (name, sb.ToString ());
+                       if (!value.Equals (""))
+                               parameters [name.ToUpper ().Trim ()] = value;
+
+                       SetDefaultConnectionParameters (parameters);
+                       SetProperties (parameters);
+
+                       this.connectionString = connectionString;
+               }
+
+               private void SetDefaultConnectionParameters (NameValueCollection parameters)
+               {
+                       if (null == parameters.Get ("APPLICATION NAME"))
+                               parameters["APPLICATION NAME"] = "Mono SybaseClient Data Provider";
+                       if (null == parameters.Get ("CONNECT TIMEOUT") && null == parameters.Get ("CONNECTION TIMEOUT")) {
+                               parameters["CONNECT TIMEOUT"] = "15";
+                               connectionTimeout = 15;
+                       }
+                       if (null == parameters.Get ("CONNECTION LIFETIME"))
+                               parameters["CONNECTION LIFETIME"] = "0";
+                       if (null == parameters.Get ("CONNECTION RESET"))
+                               parameters["CONNECTION RESET"] = "true";
+                       if (null == parameters.Get ("ENLIST"))
+                               parameters["ENLIST"] = "true";
+                       if (null == parameters.Get ("INTEGRATED SECURITY") && null == parameters.Get ("TRUSTED_CONNECTION"))
+                               parameters["INTEGRATED SECURITY"] = "false";
+                       if (null == parameters.Get ("MAX POOL SIZE")) {
+                               parameters["MAX POOL SIZE"] = "100";
+                               maxPoolSize = 100;
+                       }
+                       if (null == parameters.Get ("MIN POOL SIZE")) {
+                               parameters["MIN POOL SIZE"] = "0";
+                               maxPoolSize = 0;
+                       }
+                       if (null == parameters.Get ("NETWORK LIBRARY") && null == parameters.Get ("NET"))
+                               parameters["NETWORK LIBRARY"] = "dbmssocn";
+                       if (null == parameters.Get ("PACKET SIZE")) {
+                               parameters["PACKET SIZE"] = "512";
+                               packetSize = 512;
                        }
+                       if (null == parameters.Get ("PERSIST SECURITY INFO"))
+                               parameters["PERSIST SECURITY INFO"] = "false";
+                       if (null == parameters.Get ("POOLING"))
+                               parameters["POOLING"] = "true";
+                       if (null == parameters.Get ("WORKSTATION ID"))
+                               parameters["WORKSTATION ID"] = Dns.GetHostByName ("localhost").HostName;
                }
 
+               private void SetProperties (NameValueCollection parameters)
+               {
+                       string value;
+                       foreach (string name in parameters) {
+                               value = parameters [name];
+
+                               switch (name) {
+                               case "APPLICATION NAME" :
+                                       parms.ApplicationName = value;
+                                       break;
+                               case "ATTACHDBFILENAME" :
+                               case "EXTENDED PROPERTIES" :
+                               case "INITIAL FILE NAME" :
+                                       break;
+                               case "CONNECT TIMEOUT" :
+                               case "CONNECTION TIMEOUT" :
+                                       connectionTimeout = Int32.Parse (value);
+                                       break;
+                               case "CONNECTION LIFETIME" :
+                                       break;
+                               case "CONNECTION RESET" :
+                                       connectionReset = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
+                                       break;
+                               case "CURRENT LANGUAGE" :
+                                       parms.Language = value;
+                                       break;
+                               case "DATA SOURCE" :
+                               case "SERVER" :
+                               case "ADDRESS" :
+                               case "ADDR" :
+                               case "NETWORK ADDRESS" :
+                                       dataSource = value;
+                                       break;
+                               case "ENLIST" :
+                                       break;
+                               case "INITIAL CATALOG" :
+                               case "DATABASE" :
+                                       parms.Database = value;
+                                       break;
+                               case "INTEGRATED SECURITY" :
+                               case "TRUSTED_CONNECTION" :
+                                       break;
+                               case "MAX POOL SIZE" :
+                                       maxPoolSize = Int32.Parse (value);
+                                       break;
+                               case "MIN POOL SIZE" :
+                                       minPoolSize = Int32.Parse (value);
+                                       break;
+                               case "NET" :
+                               case "NETWORK LIBRARY" :
+                                       if (!value.ToUpper ().Equals ("DBMSSOCN"))
+                                               throw new ArgumentException ("Unsupported network library.");
+                                       break;
+                               case "PACKET SIZE" :
+                                       packetSize = Int32.Parse (value);
+                                       break;
+                               case "PASSWORD" :
+                               case "PWD" :
+                                       parms.Password = value;
+                                       break;
+                               case "PERSIST SECURITY INFO" :
+                                       break;
+                               case "POOLING" :
+                                       pooling = !(value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
+                                       break;
+                               case "USER ID" :
+                                       parms.User = value;
+                                       break;
+                               case "WORKSTATION ID" :
+                                       parms.Hostname = value;
+                                       break;
+                               }
+                       }
+               }
 
-               static bool IsValidDatabaseName (string database)
+               private static bool IsValidDatabaseName (string database)
                {
                        if (database.Length > 32 || database.Length < 1)
                                return false;