synced with ByteFX (0.74) 11-30-2003
[mono.git] / mcs / class / ByteFX.Data / mysqlclient / Connection.cs
1 // ByteFX.Data data access components for .Net
2 // Copyright (C) 2002-2003  ByteFX, Inc.
3 //
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 // 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 // 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18 using System;
19 using System.Data;
20 using System.Collections.Specialized;
21 using System.Text;
22 using System.ComponentModel;
23 using System.Globalization;
24 using ByteFX.Data.Common;
25
26 namespace ByteFX.Data.MySqlClient
27 {
28         /// <summary>
29         /// Represents an open connection to a MySQL Server database. This class cannot be inherited.
30         /// </summary>
31         /// <include file='docs/MySqlConnection.xml' path='MyDocs/MyMembers[@name="Class"]/*'/>
32         [System.Drawing.ToolboxBitmap( typeof(MySqlConnection), "Designers.connection.bmp")]
33         [System.ComponentModel.DesignerCategory("Code")]
34         [ToolboxItem(true)]
35         public sealed class MySqlConnection : Component, IDbConnection, ICloneable
36         {
37                 internal ConnectionState                        state;
38                 private  MySqlInternalConnection        internalConnection;
39                 private  MySqlDataReader                        dataReader;
40                 private  NumberFormatInfo                       numberFormat;
41                 private  MySqlConnectionString          settings;
42
43                 /// <summary>
44                 /// Occurs when the state of the connection changes.
45                 /// </summary>
46                 public event StateChangeEventHandler    StateChange;
47
48
49                 /// <summary>
50                 /// Creates a new connection
51                 /// </summary>
52                 public MySqlConnection()
53                 {
54                         settings = new MySqlConnectionString();
55                 }
56
57                 /// <summary>
58                 /// Creates a new connection
59                 /// </summary>
60                 /// <param name="container"></param>
61                 public MySqlConnection(System.ComponentModel.IContainer container)
62                 {
63                         settings = new MySqlConnectionString();
64                 }
65     
66
67                 // Have a constructor that takes a connection string.
68                 /// <summary>
69                 /// Creates a new connection using the specified connection string.
70                 /// </summary>
71                 /// <param name="connectString"></param>
72                 public MySqlConnection(string connectString)
73                 {
74                         settings = new MySqlConnectionString(connectString);
75                 }
76
77                 /// <summary>
78                 /// Gets the name of the MySQL server to which to connect.
79                 /// </summary>
80                 #region Properties
81                 [Browsable(true)]
82                 public string DataSource
83                 {
84                         get { return settings.Host; }
85                 }
86
87                 /// <summary>
88                 /// Gets the time to wait while trying to establish a connection before terminating the attempt and generating an error.
89                 /// </summary>
90                 /// <include file='docs/MySqlConnection.xml' path='MyDocs/MyMembers[@name="ConnectionTimeout"]/*'/>
91                 [Browsable(true)]
92                 public int ConnectionTimeout
93                 {
94                         get { return settings.ConnectTimeout; }
95                 }
96                 
97                 /// <summary>
98                 /// Gets the name of the current database or the database to be used after a connection is opened.
99                 /// </summary>
100                 [Browsable(true)]
101                 public string Database
102                 {
103                         get     { return settings.Database; }
104                 }
105
106                 /// <summary>
107                 /// Indicates if this connection should use compression when communicating with the server.
108                 /// </summary>
109                 [Browsable(false)]
110                 public bool UseCompression
111                 {
112                         get { return settings.UseCompression; }
113                 }
114                 
115                 /// <summary>
116                 /// Gets the current state of the connection.
117                 /// </summary>
118                 [Browsable(false)]
119                 public ConnectionState State
120                 {
121                         get { return state; }
122                 }
123
124                 internal MySqlDataReader Reader
125                 {
126                         get { return dataReader; }
127                         set { dataReader = value; }
128                 }
129
130                 internal MySqlInternalConnection InternalConnection
131                 {
132                         get { return internalConnection; }
133                 }
134
135                 internal NumberFormatInfo NumberFormat
136                 {
137                         get 
138                         {
139                                 if (numberFormat == null)
140                                 {
141                                         numberFormat = new NumberFormatInfo();
142                                         numberFormat = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
143                                         numberFormat.NumberDecimalSeparator = ".";
144                                 }
145                                 return numberFormat;
146                         }
147                 }
148
149                 /// <summary>
150                 /// Gets a string containing the version of the MySQL server to which the client is connected.
151                 /// </summary>
152                 [Browsable(false)]
153                 public string ServerVersion 
154                 {
155                         get { return  internalConnection.Driver.Version; }
156                 }
157
158                 internal Encoding Encoding 
159                 {
160                         get 
161                         {
162                                 if (internalConnection == null)
163                                         return System.Text.Encoding.Default;
164                                 else 
165                                         return internalConnection.Driver.Encoding;
166                         }
167                 }
168
169
170                 /// <summary>
171                 /// Gets or sets the string used to connect to a MySQL Server database.
172                 /// </summary>
173                 /// <include file='docs/MySqlConnection.xml' path='MyDocs/MyMembers[@name="ConnectionString"]/*'/>
174 #if WINDOWS
175                 [Editor(typeof(Designers.ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
176 #endif
177                 [Browsable(true)]
178                 [Category("Data")]
179                 public string ConnectionString
180                 {
181                         get
182                         {
183                                 // Always return exactly what the user set.
184                                 // Security-sensitive information may be removed.
185                                 return settings.ConnectString;
186                         }
187                         set
188                         {
189                                 settings.ConnectString = value;
190                                 if (internalConnection != null)
191                                         internalConnection.Settings = settings;
192                         }
193                 }
194
195                 #endregion
196
197                 #region Transactions
198                 /// <summary>
199                 /// Begins a database transaction.
200                 /// </summary>
201                 /// <returns></returns>
202                 public MySqlTransaction BeginTransaction()
203                 {
204                         if (state != ConnectionState.Open)
205                                 throw new MySqlException("Invalid operation: The connection is closed");
206
207                         MySqlTransaction t = new MySqlTransaction();
208                         t.Connection = this;
209                         InternalConnection.Driver.SendCommand( DBCmd.QUERY, "BEGIN");
210                         return t;
211                 }
212
213                 /// <summary>
214                 /// 
215                 /// </summary>
216                 IDbTransaction IDbConnection.BeginTransaction()
217                 {
218                         return BeginTransaction();
219                 }
220
221                 /// <summary>
222                 /// 
223                 /// </summary>
224                 /// <param name="level"></param>
225                 /// <returns></returns>
226                 public MySqlTransaction BeginTransaction(IsolationLevel level)
227                 {
228                         if (state != ConnectionState.Open)
229                                 throw new MySqlException("Invalid operation: The connection is closed");
230
231                         MySqlTransaction t = new MySqlTransaction();
232                         t.Connection = this;
233                         t.IsolationLevel = level;
234                         string cmd = "SET SESSION TRANSACTION ISOLATION LEVEL ";
235                         switch (level) 
236                         {
237                                 case IsolationLevel.ReadCommitted:
238                                         cmd += "READ COMMITTED"; break;
239                                 case IsolationLevel.ReadUncommitted:
240                                         cmd += "READ UNCOMMITTED"; break;
241                                 case IsolationLevel.RepeatableRead:
242                                         cmd += "REPEATABLE READ"; break;
243                                 case IsolationLevel.Serializable:
244                                         cmd += "SERIALIZABLE"; break;
245                                 case IsolationLevel.Chaos:
246                                         throw new NotSupportedException("Chaos isolation level is not supported");
247                         }
248                         InternalConnection.Driver.SendCommand( DBCmd.QUERY, cmd );
249                         InternalConnection.Driver.SendCommand( DBCmd.QUERY, "BEGIN");
250                         return t;
251                 }
252
253                 /// <summary>
254                 /// 
255                 /// </summary>
256                 /// <param name="level"></param>
257                 /// <returns></returns>
258                 IDbTransaction IDbConnection.BeginTransaction(IsolationLevel level)
259                 {
260                         return BeginTransaction(level);
261                 }
262                 #endregion
263
264                 /// <summary>
265                 /// Changes the current database for an open MySqlConnection.
266                 /// </summary>
267                 /// <param name="dbName"></param>
268                 public void ChangeDatabase(string dbName)
269                 {
270                         if (state != ConnectionState.Open)
271                                 throw new MySqlException("Invalid operation: The connection is closed");
272
273                         //TODOinternalConnection.ChangeDatabase( dbName );
274                         InternalConnection.Driver.SendCommand( DBCmd.INIT_DB, dbName );
275                 }
276
277                 internal void SetState( ConnectionState newState ) 
278                 {
279                         ConnectionState oldState = state;
280                         state = newState;
281                         if (this.StateChange != null)
282                                 StateChange(this, new StateChangeEventArgs( oldState, newState ));
283                 }
284
285                 /// <summary>
286                 /// Opens a database connection with the property settings specified by the ConnectionString.
287                 /// </summary>
288                 public void Open()
289                 {
290                         if (state == ConnectionState.Open)
291                                 throw new MySqlException("error connecting: The connection is already Open (state=Open).");
292
293                         SetState( ConnectionState.Connecting );
294
295                         if (settings.Pooling) 
296                         {
297                                 internalConnection = MySqlPoolManager.GetConnection( settings );
298                         }
299                         else
300                         {
301                                 internalConnection = new MySqlInternalConnection( settings );
302                                 internalConnection.Open();
303                         }
304
305                         SetState( ConnectionState.Open );
306                         internalConnection.SetServerVariables(this);
307                         ChangeDatabase( settings.Database );
308                 }
309
310
311                 /// <summary>
312                 /// Closes the connection to the database. This is the preferred method of closing any open connection.
313                 /// </summary>
314                 public void Close()
315                 {
316                         if (state == ConnectionState.Closed) return;
317
318                         if (dataReader != null)
319                                 dataReader.Close();
320
321                         if (settings.Pooling)
322                                 MySqlPoolManager.ReleaseConnection( internalConnection );
323                         else
324                                 internalConnection.Close();
325
326                         SetState( ConnectionState.Closed );
327                 }
328
329                 IDbCommand IDbConnection.CreateCommand()
330                 {
331                         return CreateCommand();
332                 }
333
334                 /// <summary>
335                 /// Creates and returns a MySqlCommand object associated with the MySqlConnection.
336                 /// </summary>
337                 /// <returns></returns>
338                 public MySqlCommand CreateCommand()
339                 {
340                         // Return a new instance of a command object.
341                         MySqlCommand c = new MySqlCommand();
342                         c.Connection = this;
343                         return c;
344                 }
345
346                 #region ICloneable
347                 /// <summary>
348                 /// Creates a new MySqlConnection object with the exact same ConnectionString value
349                 /// </summary>
350                 /// <returns>A cloned MySqlConnection object</returns>
351                 object ICloneable.Clone()
352                 {
353                         MySqlConnection clone = new MySqlConnection();
354                         clone.ConnectionString = this.ConnectionString;
355                         //TODO:  how deep should this go?
356                         return clone;
357                 }
358                 #endregion
359
360                 #region IDisposeable
361                 /// <summary>
362                 /// Releases the resources used by the MySqlConnection.
363                 /// </summary>
364                 public new void Dispose() 
365                 {
366                         if (State == ConnectionState.Open)
367                                 Close();
368                         base.Dispose();
369                 }
370                 #endregion
371   }
372 }