context: // Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
  //
  // MySQL Connector/NET is licensed under the terms of the GPLv2
  // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most 
  // MySQL Connectors. There are special exceptions to the terms and 
  // conditions of the GPLv2 as it is applied to this software, see the 
  // FLOSS License Exception
  // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  //
  // This program is free software; you can redistribute it and/or modify 
  // it under the terms of the GNU General Public License as published 
  // by the Free Software Foundation; version 2 of the License.
  //
  // This program is distributed in the hope that it will be useful, but 
  // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
  // for more details.
  //
  // You should have received a copy of the GNU General Public License along 
  // with this program; if not, write to the Free Software Foundation, Inc., 
  // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  
  using System;
  using System.ComponentModel;
  using System.Data;
  using System.Data.Common;
  #if !CF
  using System.Drawing;
  using System.Drawing.Design;
  using System.Transactions;
  #endif
  using System.Text;
  using IsolationLevel=System.Data.IsolationLevel;
  using MySql.Data.Common;
  using System.Diagnostics;
  using MySql.Data.MySqlClient.Properties;
  
  namespace MySql.Data.MySqlClient
  {
      /// <include file='docs/MySqlConnection.xml' path='docs/ClassSummary/*'/>
  #if !CF
      [ToolboxBitmap(typeof (MySqlConnection), "MySqlClient.resources.connection.bmp")]
      [DesignerCategory("Code")]
      [ToolboxItem(true)]
  #endif
      public sealed class MySqlConnection : DbConnection, ICloneable
      {
          internal ConnectionState connectionState;
          internal Driver driver;
          private MySqlConnectionStringBuilder settings;
          private bool hasBeenOpen;
          private SchemaProvider schemaProvider;
          private ProcedureCache procedureCache;
          private bool isInUse;
  #if !CF
          private PerformanceMonitor perfMonitor;
  #endif
          private bool isKillQueryConnection;
          private string database;
          private int commandTimeout;
  
          /// <include file='docs/MySqlConnection.xml' path='docs/InfoMessage/*'/>
          public event MySqlInfoMessageEventHandler InfoMessage;
  
          private static Cache<string, MySqlConnectionStringBuilder> connectionStringCache =
              new Cache<string, MySqlConnectionStringBuilder>(0, 25);
  
          /// <include file='docs/MySqlConnection.xml' path='docs/DefaultCtor/*'/>
          public MySqlConnection()
          {
              //TODO: add event data to StateChange docs
              settings = new MySqlConnectionStringBuilder();
              database = String.Empty;
          }
  
          /// <include file='docs/MySqlConnection.xml' path='docs/Ctor1/*'/>
          public MySqlConnection(string connectionString)
              : this()
          {
              ConnectionString = connectionString;
          }
  
          #region Interal Methods & Properties
  
  #if !CF
          internal PerformanceMonitor PerfMonitor
          {
              get { return perfMonitor; }
          }
  
  #endif
  
          internal ProcedureCache ProcedureCache
          {
              get { return procedureCache; }
          }
  
          internal MySqlConnectionStringBuilder Settings
          {
              get { return settings; }
          }
  
          internal MySqlDataReader Reader
          {
              get 
              { 
                  if (driver == null)
                      return null;
                  return driver.reader;
              }
              set 
              { 
                  driver.reader = value;
                  isInUse = driver.reader != null;
              }
          }
  
          internal void OnInfoMessage(MySqlInfoMessageEventArgs args)
          {
              if (InfoMessage != null)
              {
                  InfoMessage(this, args);
              }
          }
  
          internal bool SoftClosed
          {
              get 
              {
  #if !CF
                  return (State == ConnectionState.Closed) && 
                      driver != null && 
                      driver.CurrentTransaction != null;
  #else
                  return false;            
  #endif
              }
          }
  
          internal bool IsInUse
          {
              get{ return isInUse; }
              set{ isInUse = value; }
          }
  
          #endregion
  
          #region Properties
  
          /// <summary>
          /// Returns the id of the server thread this connection is executing on
          /// </summary>
  #if !CF
          [Browsable(false)]
  #endif
              public int ServerThread
          {
              get { return driver.ThreadID; }
          }
  
          /// <summary>
          /// Gets the name of the MySQL server to which to connect.
          /// </summary>
  #if !CF
          [Browsable(true)]
  #endif
              public override string DataSource
          {
              get { return settings.Server; }
          }
  
          /// <include file='docs/MySqlConnection.xml' path='docs/ConnectionTimeout/*'/>
  #if !CF
          [Browsable(true)]
  #endif
              public override int ConnectionTimeout
          {
              get { return (int) settings.ConnectionTimeout; }
          }
  
          /// <include file='docs/MySqlConnection.xml' path='docs/Database/*'/>
  #if !CF
          [Browsable(true)]
  #endif
              public override string Database
          {
              get { return database; }
          }
  
          /// <summary>
          /// Indicates if this connection should use compression when communicating with the server.
          /// </summary>
  #if !CF
          [Browsable(false)]
  #endif
              public bool UseCompression
          {
              get { return settings.UseCompression; }
          }
  
          /// <include file='docs/MySqlConnection.xml' path='docs/State/*'/>
  #if !CF
          [Browsable(false)]
  #endif
              public override ConnectionState State
          {
              get { return connectionState; }
          }
  
          /// <include file='docs/MySqlConnection.xml' path='docs/ServerVersion/*'/>
  #if !CF
          [Browsable(false)]
  #endif
              public override string ServerVersion
          {
              get { return driver.Version.ToString(); }
          }
  
          /// <include file='docs/MySqlConnection.xml' path='docs/ConnectionString/*'/>
  #if !CF
          [Editor("MySql.Data.MySqlClient.Design.ConnectionStringTypeEditor,MySqlClient.Design", typeof (UITypeEditor))]
          [Browsable(true)]
          [Category("Data")]
          [Description(
              "Information used to connect to a DataSource, such as 'Server=xxx;UserId=yyy;Password=zzz;Database=dbdb'.")]
  #endif
              public override string ConnectionString
          {
              get
              {
                  // Always return exactly what the user set.
                  // Security-sensitive information may be removed.
                  return settings.GetConnectionString(!hasBeenOpen || settings.PersistSecurityInfo);
              }
              set
              {
                  if (State != ConnectionState.Closed)
                      throw new MySqlException(
                          "Not allowed to change the 'ConnectionString' property while the connection (state=" + State +
                          ").");
  
                  MySqlConnectionStringBuilder newSettings;
                  lock (connectionStringCache)
                  {
                      if (value == null)
                          newSettings = new MySqlConnectionStringBuilder();
                      else
                      {
                          newSettings = (MySqlConnectionStringBuilder)connectionStringCache[value];
                          if (null == newSettings)
                          {
                              newSettings = new MySqlConnectionStringBuilder(value);
                              connectionStringCache.Add(value, newSettings);
                          }
                      }
                  }
  
                  settings = newSettings;
  
                  if (settings.Database != null && settings.Database.Length > 0)
                      this.database = settings.Database;
  
                  if (driver != null)
                      driver.Settings = newSettings;
              }
          }
  
  #if !CF && !__MonoCS__
  
          protected override DbProviderFactory DbProviderFactory
          {
              get
              {
                  return MySqlClientFactory.Instance;
              }
          }
  		
  #endif
  
          #endregion
  
          #region Transactions
  
  #if !MONO && !CF
          /// <summary>
          /// Enlists in the specified transaction. 
          /// </summary>
          /// <param name="transaction">
          /// A reference to an existing <see cref="System.Transactions.Transaction"/> in which to enlist.
          /// </param>
          public override void EnlistTransaction(Transaction transaction)
          {
              // enlisting in the null transaction is a noop
              if (transaction == null)
                  return;
  
              // guard against trying to enlist in more than one transaction
              if (driver.CurrentTransaction != null)
              {
                  if (driver.CurrentTransaction.BaseTransaction == transaction)
                      return;
  
                  throw new MySqlException("Already enlisted");
              }
  
              // now see if we need to swap out drivers.  We would need to do this since
              // we have to make sure all ops for a given transaction are done on the
              // same physical connection.
              Driver existingDriver = DriverTransactionManager.GetDriverInTransaction(transaction);
              if (existingDriver != null)
              {
                  // we can't allow more than one driver to contribute to the same connection
                  if (existingDriver.IsInActiveUse)
                      throw new NotSupportedException(Resources.MultipleConnectionsInTransactionNotSupported);
  
                  // there is an existing driver and it's not being currently used.
                  // now we need to see if it is using the same connection string
                  string text1 = existingDriver.Settings.ConnectionString;
                  string text2 = Settings.ConnectionString;
                  if (String.Compare(text1, text2, true) != 0)
                      throw new NotSupportedException(Resources.MultipleConnectionsInTransactionNotSupported);
  
                  // close existing driver
                  // set this new driver as our existing driver
                  CloseFully();
                  driver = existingDriver;
              }
  
  
gt:             if (driver.CurrentTransaction == null)