2 // Mono.Data.MySql.MyConnection.cs
5 // Daniel Morgan (danmorg@sc.rr.com)
6 // Tim Coleman (tim@timcoleman.com)
8 // (C) Daniel Morgan 2002
9 // Copyright (C) Tim Coleman, 2002
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Collections
;
35 using System
.Collections
.Specialized
;
36 using System
.ComponentModel
;
38 using System
.Data
.Common
;
39 using System
.Runtime
.InteropServices
;
42 namespace Mono
.Data
.MySql
{
44 public sealed class MySqlConnection
: Component
, ICloneable
, IDbConnection
{
48 private IntPtr mysqlInitStruct
= IntPtr
.Zero
;
49 private IntPtr mysqlConn
= IntPtr
.Zero
;
51 private string connectionString
= "";
52 private string mysqlConnectionString
= "";
54 private MySqlTransaction trans
= null;
55 private int connectionTimeout
= 15;
56 // default for 15 seconds
58 // MySQL connection string parameters
63 uint port
= MySql
.Port
;
64 string socketName
= "";
68 private ConnectionState conState
= ConnectionState
.Closed
;
71 //private MySqlDataReader rdr = null;
72 private bool dataReaderOpen
= false;
73 // FIXME: if true, throw an exception if SqlConnection
74 // is used for anything other than reading
75 // data using SqlDataReader
77 private string versionString
= "Unknown";
78 private bool disposed
= false;
84 // A lot of the defaults were initialized in the Fields
86 public MySqlConnection () {
91 public MySqlConnection (String connectionString
) {
92 SetConnectionString (connectionString
);
95 #endregion // Constructors
99 protected override void Dispose(bool disposing
) {
103 // release any managed resources
106 // release any unmanaged resources
107 mysqlInitStruct
= IntPtr
.Zero
;
108 IntPtr mysqlConn
= IntPtr
.Zero
;
112 this.disposed
= true;
115 base.Dispose(disposing
);
124 #endregion // Destructors
126 #region Public Methods
128 IDbTransaction IDbConnection
.BeginTransaction () {
129 return BeginTransaction ();
132 public MySqlTransaction
BeginTransaction () {
133 return TransactionBegin (); // call private method
136 IDbTransaction IDbConnection
.BeginTransaction (IsolationLevel
138 return BeginTransaction (il
);
141 public MySqlTransaction
BeginTransaction (IsolationLevel il
) {
142 return TransactionBegin (il
); // call private method
146 public MySqlTransaction
BeginTransaction(string transactionName
) {
148 // FIXME: Can MySQL handle named transactions?
149 return TransactionBegin (); // call private method
153 public MySqlTransaction
BeginTransaction(IsolationLevel iso
,
154 string transactionName
) {
156 // FIXME: Can MySQL handle named transactions?
157 return TransactionBegin (iso
); // call private method
160 public void ChangeDatabase (string databaseName
) {
161 dbname
= databaseName
;
162 int sdb
= MySql
.SelectDb(mysqlInitStruct
, dbname
);
166 "Can not select the " +
168 " database because: " +
169 MySql
.Error(mysqlInitStruct
);
170 throw new MySqlException (msg
);
174 object ICloneable
.Clone() {
175 throw new NotImplementedException ();
179 public void Close () {
180 if(dataReaderOpen
== true) {
181 // TODO: what do I do if
182 // the user Closes the connection
183 // without closing the Reader first?
189 IDbCommand IDbConnection
.CreateCommand () {
190 return CreateCommand ();
193 public MySqlCommand
CreateCommand () {
194 MySqlCommand sqlcmd
= new MySqlCommand ("", this);
200 public void Open () {
201 if(dbname
.Equals(""))
202 throw new InvalidOperationException(
204 else if(conState
== ConnectionState
.Open
)
205 throw new InvalidOperationException(
206 "ConnnectionState is already Open");
207 else if(connectionString
.Equals(String
.Empty
))
208 throw new InvalidOperationException(
209 "ConnectionString is not set");
211 // FIXME: check to make sure we have
212 // everything to connect,
213 // otherwise, throw an exception
215 mysqlInitStruct
= MySql
.Init(IntPtr
.Zero
);
216 if (mysqlInitStruct
== IntPtr
.Zero
) {
217 throw new MySqlException("MySQL Init failed.");
221 // *** this is what it should be ***
222 //mysqlConn = MySql.Connect(mysqlInitStruct,
223 // host.Equals("") ? null : host,
224 // user.Equals("") ? null : user,
225 // passwd.Equals("") ? null : passwd,
226 // dbname.Equals("") ? null : dbname,
228 // socketName.Equals("") ? null : socketName,
231 mysqlConn
= MySql
.Connect(mysqlInitStruct
,
239 if (mysqlConn
== IntPtr
.Zero
) {
240 string msg
= "MySQL Connect failed, " +
241 MySql
.Error(mysqlInitStruct
);
242 throw new MySqlException(msg
);
245 this.ChangeDatabase (dbname
);
247 // Successfully Connected
251 #endregion // Public Methods
253 #region Protected Methods
257 #region Internal Methods
259 // Used to prevent MySqlConnection
260 // from doing anything while
261 // MySqlDataReader is open.
262 // Open the Reader. (called from MySqlCommand)
264 internal void OpenReader(MySqlDataReader reader) {
265 if(dataReaderOpen == true) {
266 // TODO: throw exception here?
272 dataReaderOpen = true;
277 // Used to prevent MySqlConnection
278 // from doing anything while
279 // MySqlDataReader is open
280 // Close the Reader (called from MySqlCommand)
281 // if closeConnection true, Close() the connection
282 // this is based on CommandBehavior.CloseConnection
283 internal void CloseReader(bool closeConnection
) {
284 if(closeConnection
== true)
287 dataReaderOpen
= false;
290 #endregion // Internal Methods
292 #region Private Methods
294 private void SetupConnection() {
295 conState
= ConnectionState
.Open
;
297 versionString
= GetDatabaseServerVersion();
300 private string GetDatabaseServerVersion() {
301 MySqlCommand cmd
= new MySqlCommand("select version()",this);
302 return (string) cmd
.ExecuteScalar();
305 private void CloseDataSource () {
306 // FIXME: just a quick hack
307 if(conState
== ConnectionState
.Open
) {
310 if(trans.DoingTransaction == true) {
316 conState
= ConnectionState
.Closed
;
317 MySql
.Close(mysqlInitStruct
);
319 mysqlConn
= IntPtr
.Zero
;
323 void SetConnectionString (string connectionString
) {
324 this.connectionString
= connectionString
;
326 connectionString
+= ";";
327 NameValueCollection parameters
= new NameValueCollection ();
329 if (connectionString
== String
.Empty
)
332 bool inQuote
= false;
333 bool inDQuote
= false;
335 string name
= String
.Empty
;
336 string value = String
.Empty
;
337 StringBuilder sb
= new StringBuilder ();
339 foreach (char c
in connectionString
) {
345 inDQuote
= !inDQuote
;
348 if (!inDQuote
&& !inQuote
) {
349 if (name
!= String
.Empty
&& name
!= null) {
350 value = sb
.ToString ();
351 parameters
[name
.ToUpper ().Trim ()] = value.Trim ();
354 value = String
.Empty
;
355 sb
= new StringBuilder ();
361 if (!inDQuote
&& !inQuote
) {
362 name
= sb
.ToString ();
363 sb
= new StringBuilder ();
374 SetProperties (parameters
);
377 private void SetProperties (NameValueCollection parameters
) {
379 StringBuilder connectionStr
= new StringBuilder();
382 foreach (string name
in parameters
) {
383 value = parameters
[name
];
388 port
= UInt32
.Parse(value);
393 // set DataSource property
396 case "INITIAL CATALOG" :
399 // set Database property
416 // FIXME: how to get these flags and
417 // and pass to MySQL?
418 // flags is a bitfield
419 flags
= UInt32
.Parse(value);
423 // FIXME: throw exception?
427 string valuePair
= name
+ "=" + value;
428 connectionStr
.Append (valuePair
+ " ");
431 this.mysqlConnectionString
= connectionStr
.ToString ();
434 private MySqlTransaction
TransactionBegin () {
435 // FIXME: need to keep track of
436 // transaction in-progress
437 trans
= new MySqlTransaction ();
438 // using internal methods of SqlTransaction
439 trans
.SetConnection (this);
445 private MySqlTransaction
TransactionBegin (IsolationLevel il
) {
446 // FIXME: need to keep track of
447 // transaction in-progress
448 trans
= new MySqlTransaction ();
449 // using internal methods of MySqlTransaction
450 trans
.SetConnection (this);
451 trans
.SetIsolationLevel (il
);
459 #region Public Properties
462 public ConnectionState State
{
468 public string ConnectionString
{
470 return connectionString
;
473 SetConnectionString (value);
477 public int ConnectionTimeout
{
479 return connectionTimeout
;
483 public string Database
{
489 public string DataSource
{
495 public int PacketSize
{
497 throw new NotImplementedException ();
501 public string ServerVersion
{
503 return versionString
;
507 #endregion // Public Properties
509 #region Internal Properties
511 // For Mono.Data.MySql classes
512 // to get the current transaction
513 // in progress - if any
514 internal MySqlTransaction Transaction
{
520 // For Mono.Data.MySql classes
521 // to get the unmanaged MySql connection
522 internal IntPtr NativeMySqlConnection
{
528 // For Mono.Data.MySql classes
529 // to get the unmanaged MySql connection
530 internal IntPtr NativeMySqlInitStruct
{
532 return mysqlInitStruct
;
536 // Used to prevent SqlConnection
537 // from doing anything while
538 // SqlDataReader is open
539 internal bool IsReaderOpen
{
541 return dataReaderOpen
;
545 #endregion // Internal Properties
550 MyInfoMessageEventHandler InfoMessage;
553 StateChangeEventHandler StateChange;