2002-10-22 Tim Coleman (tim@timcoleman.com)
[mono.git] / mcs / class / Mono.Data.TdsClient / Mono.Data.TdsClient / TdsConnection.cs
1 //
2 // Mono.Data.TdsClient.TdsConnection.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //
7 // Copyright (C) 2002 Tim Coleman
8 //
9
10 using Mono.Data.TdsClient.Internal;
11 using System;
12 using System.Collections;
13 using System.Collections.Specialized;
14 using System.ComponentModel;
15 using System.Data;
16 using System.Net;
17 using System.Text;
18
19 namespace Mono.Data.TdsClient {
20         public class TdsConnection : Component, ICloneable, IDbConnection
21         {
22                 #region Fields
23
24                 bool autoCommit = true;
25                 bool disablePooling = false;
26                 string connectionString = null;
27                 int connectionTimeout = 15;
28                 string database;
29                 IsolationLevel isolationLevel = IsolationLevel.ReadCommitted;
30                 int minPoolSize;
31                 int maxPoolSize;
32                 ConnectionState state = ConnectionState.Closed;
33
34                 TdsConnectionParameters parms = new TdsConnectionParameters ();
35                 TdsTransaction transaction = null;
36
37                 // This is the collection of connection pools available
38                 static Hashtable pools = new Hashtable ();
39
40                 // Our TDS object, the real workhorse
41                 Tds tds = null;
42
43                 #endregion // Fields
44
45                 #region Constructors
46
47                 public TdsConnection ()
48                         : this (String.Empty)
49                 {
50                 }
51
52                 public TdsConnection (string connectionString)
53                 {
54                         parms.PacketSize = 512;
55                         parms.TdsVersion = TdsVersion.tds42;
56                         parms.User = null;
57                         parms.Password = null;
58                         SetConnectionString (connectionString);
59                 }
60                         
61                 #endregion // Constructors
62
63                 #region Properties
64
65                 public string ConnectionString {
66                         get { return connectionString; }
67                         set { SetConnectionString (value); }
68                 }
69
70                 public string Database {
71                         get { return parms.Database; }
72                 }
73
74                 public string DataSource {
75                         get { return parms.DataSource; }
76                 }
77
78                 public ConnectionState State {
79                         get { return state; }
80                 }
81                 
82                 public int ConnectionTimeout {
83                         get { return connectionTimeout; }
84                 }
85
86                 public int PacketSize {
87                         get { return parms.PacketSize; }
88                 }
89
90                 public string User {
91                         get { return parms.User; }
92                 }
93
94                 public string Password {
95                         get { return parms.Password; }
96                 }
97
98                 internal Tds Tds {
99                         get { return tds; }
100                 }
101                 
102                 #endregion // Properties
103
104                 #region Methods
105
106                 private static Tds AllocateTds (TdsConnectionParameters parms, string connectionString, bool disablePooling, int minPoolSize, int maxPoolSize)
107                 {
108                         if (disablePooling)
109                                 return new Tds (parms);
110
111                         TdsConnectionPool pool = (TdsConnectionPool) pools[connectionString];
112                         if (pool == null) {
113                                 lock (pools) {
114                                         pool = new TdsConnectionPool (parms, minPoolSize, maxPoolSize);
115                                         pools[connectionString] = pool;
116                                 }
117                         }
118
119                         return pool.FindAnAvailableTds ();
120                 }
121
122                 public TdsTransaction BeginTransaction ()
123                 {
124                         return BeginTransaction (IsolationLevel.ReadCommitted);
125                 }
126
127                 public TdsTransaction BeginTransaction (IsolationLevel il)
128                 {
129                         if (state == ConnectionState.Closed)
130                                 throw new InvalidOperationException ("Invalid operation. The connection is closed.");
131                         if (transaction != null && transaction.Open)
132                                 throw new InvalidOperationException ("TdsConnection does not support parallel transactions.");
133
134                         transaction = new TdsTransaction (this, il);
135                         return transaction;
136                 }
137
138                 public void ChangeDatabase (string databaseName)
139                 {
140                         if (Database == databaseName)
141                                 return;
142
143                         tds.ChangeDatabase (databaseName);
144                 }
145
146                 public void Close ()
147                 {
148                         // rollback any open transactions
149                         if (transaction.Open)
150                                 transaction.Rollback ();
151
152                         // if we aren't pooling, just close the connection
153                         // otherwise, just set the InUse flag to false
154                         if (disablePooling)
155                                 tds.Close ();
156                         else
157                                 tds.InUse = false;
158                         this.state = ConnectionState.Closed;
159                 }
160
161                 public TdsCommand CreateCommand ()
162                 {
163                         TdsCommand command = new TdsCommand ();
164                         command.Connection = this; 
165                         return command;
166                 }
167
168                 object ICloneable.Clone()
169                 {
170                         throw new NotImplementedException ();
171                 }
172
173                 IDbTransaction IDbConnection.BeginTransaction ()
174                 {
175                         return BeginTransaction ();
176                 }
177
178                 IDbTransaction IDbConnection.BeginTransaction (IsolationLevel il)
179                 {
180                         return BeginTransaction (il);
181                 }
182
183                 IDbCommand IDbConnection.CreateCommand ()
184                 {
185                         return CreateCommand ();
186                 }
187
188                 public void Open ()
189                 {
190                         if (connectionString == null)
191                                 throw new InvalidOperationException ("The ConnectionString property has not been initialized.");
192                         if (User == null)
193                         {
194                                 throw new ArgumentException ();
195                         }
196                         if (Password == null)
197                         {
198                                 throw new ArgumentException ();
199                         }
200
201                         tds = AllocateTds (parms, connectionString, disablePooling, minPoolSize, maxPoolSize);
202                         tds.InUse = true;
203                         tds.Logon (parms);
204                         this.state = ConnectionState.Open;
205                 }
206
207                 [MonoTODO]
208                 private void SetConnectionString (string connectionString)
209                 {
210                         connectionString += ";";
211                         NameValueCollection parameters = new NameValueCollection ();
212
213                         if (connectionString == String.Empty)
214                                 return;
215
216                         bool inQuote = false;
217                         bool inDQuote = false;
218
219                         string name = String.Empty;
220                         string value = String.Empty;
221                         StringBuilder sb = new StringBuilder ();
222
223                         foreach (char c in connectionString)
224                         {
225                                 switch (c) {
226                                 case '\'':
227                                         inQuote = !inQuote;
228                                         break;
229                                 case '"' :
230                                         inDQuote = !inDQuote;
231                                         break;
232                                 case ';' :
233                                         if (!inDQuote && !inQuote) {
234                                                 value = sb.ToString ();
235                                                 sb = new StringBuilder ();
236                                         }
237                                         else
238                                                 sb.Append (c);
239                                         break;
240                                 case '=' :
241                                         if (!inDQuote && !inQuote) {
242                                                 name = sb.ToString ();
243                                                 sb = new StringBuilder ();
244                                         }
245                                         else
246                                                 sb.Append (c);
247                                         break;
248                                 default:
249                                         sb.Append (c);
250                                         break;
251                                 }
252                                 if (value != String.Empty) {
253                                         parameters [name.ToUpper ().Trim ()] = value.Trim ();
254                                         name = String.Empty;
255                                         value = String.Empty;
256                                 } 
257                         }
258
259                         if (this.ConnectionString == null)
260                         {
261                                 SetDefaultConnectionParameters (parameters);
262                         }
263
264                         SetProperties (parameters);
265
266                         this.connectionString = connectionString;
267                 }
268
269
270                 private void SetDefaultConnectionParameters (NameValueCollection parameters)
271                 {
272                         if (null == parameters.Get ("APPLICATION NAME"))
273                                 parameters["APPLICATION NAME"] = ".Net SqlClient Data Provider";
274                         if (null == parameters.Get ("CONNECT TIMEOUT") && null == parameters.Get ("CONNECTION TIMEOUT"))
275                                 parameters["CONNECT TIMEOUT"] = "15";
276                         if (null == parameters.Get ("CONNECTION LIFETIME"))
277                                 parameters["CONNECTION LIFETIME"] = "0";
278                         if (null == parameters.Get ("CONNECTION RESET"))
279                                 parameters["CONNECTION RESET"] = "true";
280                         if (null == parameters.Get ("ENLIST"))
281                                 parameters["ENLIST"] = "true";
282                         if (null == parameters.Get ("INTEGRATED SECURITY") && null == parameters.Get ("TRUSTED_CONNECTION"))
283                                 parameters["INTEGRATED SECURITY"] = "false";
284                         if (null == parameters.Get ("MAX POOL SIZE"))
285                                 parameters["MAX POOL SIZE"] = "100";
286                         if (null == parameters.Get ("MIN POOL SIZE"))
287                                 parameters["MIN POOL SIZE"] = "0";
288                         if (null == parameters.Get ("NETWORK LIBRARY") && null == parameters.Get ("NET"))
289                                 parameters["NETWORK LIBRARY"] = "dbmssocn";
290                         if (null == parameters.Get ("PACKET SIZE"))
291                                 parameters["PACKET SIZE"] = "8192";
292                         if (null == parameters.Get ("PERSIST SECURITY INFO"))
293                                 parameters["PERSIST SECURITY INFO"] = "false";
294                         if (null == parameters.Get ("POOLING"))
295                                 parameters["POOLING"] = "true";
296                         if (null == parameters.Get ("WORKSTATION ID"))
297                                 parameters["WORKSTATION ID"] = Dns.GetHostByName ("localhost").HostName;
298                 }
299
300                 private void SetProperties (NameValueCollection parameters)
301                 {
302                         string value;
303                         foreach (string name in parameters) {
304                                 value = parameters[name];
305
306                                 switch (name) {
307                                 case "APPLICATION NAME" :
308                                         parms.ApplicationName = value;
309                                         break;
310                                 case "ATTACHDBFILENAME" :
311                                 case "EXTENDED PROPERTIES" :
312                                 case "INITIAL FILE NAME" :
313                                         break;
314                                 case "CONNECT TIMEOUT" :
315                                 case "CONNECTION TIMEOUT" :
316                                         connectionTimeout = Int32.Parse (value);
317                                         break;
318                                 case "CONNECTION LIFETIME" :
319                                         break;
320                                 case "CONNECTION RESET" :
321                                         break;
322                                 case "CURRENT LANGUAGE" :
323                                         parms.Language = value;
324                                         break;
325                                 case "DATA SOURCE" :
326                                 case "SERVER" :
327                                 case "ADDRESS" :
328                                 case "ADDR" :
329                                 case "NETWORK ADDRESS" :
330                                         parms.DataSource = value;
331                                         break;
332                                 case "ENLIST" :
333                                         break;
334                                 case "INITIAL CATALOG" :
335                                 case "DATABASE" :
336                                         parms.Database = value;
337                                         break;
338                                 case "INTEGRATED SECURITY" :
339                                 case "TRUSTED_CONNECTION" :
340                                         break;
341                                 case "MAX POOL SIZE" :
342                                         maxPoolSize = Int32.Parse (value);
343                                         break;
344                                 case "MIN POOL SIZE" :
345                                         minPoolSize = Int32.Parse (value);
346                                         break;
347                                 case "NET" :
348                                 case "NETWORK LIBRARY" :
349                                         if (!value.ToUpper ().Equals ("DBMSSOCN"))
350                                                 throw new TdsException ("Unsupported network library.");
351                                         break;
352                                 case "PACKET SIZE" :
353                                         parms.PacketSize = Int32.Parse (value);
354                                         break;
355                                 case "PASSWORD" :
356                                 case "PWD" :
357                                         parms.Password = value;
358                                         break;
359                                 case "PERSIST SECURITY INFO" :
360                                         break;
361                                 case "POOLING" :
362                                         disablePooling = (value.ToUpper ().Equals ("FALSE") || value.ToUpper ().Equals ("NO"));
363                                         break;
364                                 case "USER ID" :
365                                         parms.User = value;
366                                         break;
367                                 case "WORKSTATION ID" :
368                                         parms.Hostname = value;
369                                         break;
370                                 }
371                         }
372                 }
373                 #endregion // Methods
374         }
375 }