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