MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Iggy Galarza Date:June 21 2010 5:43pm
Subject:bzr commit into connector-net-6.2 branch (iggy:858) Bug#54012
View as plain text  
#At file:///C:/src/bzr.lp/mine/connectornet/6.2/ based on revid:vvaintroub@strippedpp

  858 Iggy Galarza	2010-06-21
      Bug #54012 - MySql Connector/NET is not hardened to deal with ThreadAbortException
      - Added ThreadAborted Handler modeled after the Timeout Handler.

    modified:
      MySql.Data/Provider/Properties/Resources.Designer.cs
      MySql.Data/Provider/Properties/Resources.resx
      MySql.Data/Provider/Source/Connection.cs
      MySql.Data/Provider/Source/command.cs
      MySql.Data/Provider/Source/datareader.cs
      MySql.Data/Tests/Source/Threading.cs
=== modified file 'MySql.Data/Provider/Properties/Resources.Designer.cs'
--- a/MySql.Data/Provider/Properties/Resources.Designer.cs	2010-04-27 18:30:06 +0000
+++ b/MySql.Data/Provider/Properties/Resources.Designer.cs	2010-06-21 17:43:00 +0000
@@ -1,7 +1,7 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:2.0.50727.4927
+//     Runtime Version:2.0.50727.3607
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
 //     the code is regenerated.
@@ -441,71 +441,71 @@ namespace MySql.Data.MySqlClient.Propert
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to ACCESSIBLE
-        ///ADD
-        ///ALL
-        ///ALTER
-        ///ANALYZE
-        ///AND
-        ///AS
-        ///ASC
-        ///ASENSITIVE
-        ///BEFORE
-        ///BETWEEN
-        ///BIGINT
-        ///BINARY
-        ///BLOB
-        ///BOTH
-        ///BY
-        ///CALL
-        ///CASCADE
-        ///CASE
-        ///CHANGE
-        ///CHAR
-        ///CHARACTER
-        ///CHECK
-        ///COLLATE
-        ///COLUMN
-        ///CONDITION
-        ///CONNECTION
-        ///CONSTRAINT
-        ///CONTINUE
-        ///CONVERT
-        ///CREATE
-        ///CROSS
-        ///CURRENT_DATE
-        ///CURRENT_TIME
-        ///CURRENT_TIMESTAMP
-        ///CURRENT_USER
-        ///CURSOR
-        ///DATABASE
-        ///DATABASES
-        ///DAY_HOUR
-        ///DAY_MICROSECOND
-        ///DAY_MINUTE
-        ///DAY_SECOND
-        ///DEC
-        ///DECIMAL
-        ///DECLARE
-        ///DEFAULT
-        ///DELAYED
-        ///DELETE
-        ///DESC
-        ///DESCRIBE
-        ///DETERMINISTIC
-        ///DISTINCT
-        ///DISTINCTROW
-        ///DIV
-        ///DOUBLE
-        ///DROP
-        ///DUAL
-        ///EACH
-        ///ELSE
-        ///ELSEIF
-        ///ENCLOSED
-        ///ESCAPED
-        ///EXISTS
-        ///EXIT
+        ///   Looks up a localized string similar to ACCESSIBLE
+        ///ADD
+        ///ALL
+        ///ALTER
+        ///ANALYZE
+        ///AND
+        ///AS
+        ///ASC
+        ///ASENSITIVE
+        ///BEFORE
+        ///BETWEEN
+        ///BIGINT
+        ///BINARY
+        ///BLOB
+        ///BOTH
+        ///BY
+        ///CALL
+        ///CASCADE
+        ///CASE
+        ///CHANGE
+        ///CHAR
+        ///CHARACTER
+        ///CHECK
+        ///COLLATE
+        ///COLUMN
+        ///CONDITION
+        ///CONNECTION
+        ///CONSTRAINT
+        ///CONTINUE
+        ///CONVERT
+        ///CREATE
+        ///CROSS
+        ///CURRENT_DATE
+        ///CURRENT_TIME
+        ///CURRENT_TIMESTAMP
+        ///CURRENT_USER
+        ///CURSOR
+        ///DATABASE
+        ///DATABASES
+        ///DAY_HOUR
+        ///DAY_MICROSECOND
+        ///DAY_MINUTE
+        ///DAY_SECOND
+        ///DEC
+        ///DECIMAL
+        ///DECLARE
+        ///DEFAULT
+        ///DELAYED
+        ///DELETE
+        ///DESC
+        ///DESCRIBE
+        ///DETERMINISTIC
+        ///DISTINCT
+        ///DISTINCTROW
+        ///DIV
+        ///DOUBLE
+        ///DROP
+        ///DUAL
+        ///EACH
+        ///ELSE
+        ///ELSEIF
+        ///ENCLOSED
+        ///ESCAPED
+        ///EXISTS
+        ///EXIT
         ///EXP [rest of string was truncated]&quot;;.
         /// </summary>
         public static string keywords {
@@ -839,6 +839,15 @@ namespace MySql.Data.MySqlClient.Propert
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to A thread abort request has been handled..
+        /// </summary>
+        public static string ThreadAborted {
+            get {
+                return ResourceManager.GetString("ThreadAborted", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding..
         /// </summary>
         public static string Timeout {

=== modified file 'MySql.Data/Provider/Properties/Resources.resx'
--- a/MySql.Data/Provider/Properties/Resources.resx	2010-03-11 21:02:47 +0000
+++ b/MySql.Data/Provider/Properties/Resources.resx	2010-06-21 17:43:00 +0000
@@ -457,4 +457,7 @@
   <data name="TraceQueryNormalized" xml:space="preserve">
     <value>{0}: Query Normalized: {2}</value>
   </data>
+  <data name="ThreadAborted" xml:space="preserve">
+    <value>A thread abort request has been handled.</value>
+  </data>
 </root>
\ No newline at end of file

=== modified file 'MySql.Data/Provider/Source/Connection.cs'
--- a/MySql.Data/Provider/Source/Connection.cs	2010-06-11 17:08:18 +0000
+++ b/MySql.Data/Provider/Source/Connection.cs	2010-06-21 17:43:00 +0000
@@ -55,6 +55,7 @@ namespace MySql.Data.MySqlClient
         private bool abortOnTimeout;
         private string database;
         private int commandTimeout;
+        private bool threadAbort;
 
         /// <include file='docs/MySqlConnection.xml' path='docs/InfoMessage/*'/>
         public event MySqlInfoMessageEventHandler InfoMessage;
@@ -427,7 +428,7 @@ namespace MySql.Data.MySqlClient
         /// <returns></returns>
         public bool Ping()
         {
-            if(dataReader != null)
+            if(Reader != null)
                 throw new MySqlException(Resources.DataReaderOpen);
             if (driver != null && driver.Ping())
                 return true;
@@ -627,7 +628,44 @@ namespace MySql.Data.MySqlClient
 			return cmd.ExecuteScalar().ToString();
 		}
 
+        internal void HandleException(string connector_error, Exception exception)
+        {
+            bool isFatal = false;
+
+            if (threadAbort)
+            {
+                // Special connection started to cancel a query.
+                // Timeout handler is disabled to prevent recursive connection
+                // spawning when original query and KILL time out.
+                Abort();
+                throw new MySqlException(Resources.ThreadAborted, true, exception);
+            }
 
+            try
+            {
+                // Do a fast cancel.The reason behind small values for connection
+                // and command timeout is that we do not want user to wait longer
+                // after command has already expired.
+                // Microsoft's SqlClient seems to be using 5 seconds timeouts 
+                // here as well.
+                // Read the  error packet with "interrupted" message.
+                CancelQuery(5);
+                driver.ResetTimeout(5000);
+                if (Reader != null)
+                {
+                    Reader.Close();
+                    Reader = null;
+                }
+            }
+            catch (Exception ex)
+            {
+                MySqlTrace.LogWarning(ServerThread, "Could not kill query in timeout handler, " +
+                    " aborting connection. Exception was " + ex.Message);
+                Abort();
+                isFatal = true;
+            }
+            throw new MySqlException(connector_error, isFatal, exception);
+        }
 
         internal void HandleTimeout(TimeoutException tex)
         {
@@ -682,6 +720,7 @@ namespace MySql.Data.MySqlClient
             using(MySqlConnection c = new MySqlConnection(cb.ConnectionString))
             {
                 c.abortOnTimeout = true;
+                c.threadAbort = true;
                 c.Open();
                 string commandText = "KILL QUERY " + ServerThread;
                 MySqlCommand cmd = new MySqlCommand(commandText, c);

=== modified file 'MySql.Data/Provider/Source/command.cs'
--- a/MySql.Data/Provider/Source/command.cs	2010-06-10 19:25:08 +0000
+++ b/MySql.Data/Provider/Source/command.cs	2010-06-21 17:43:00 +0000
@@ -440,6 +440,11 @@ namespace MySql.Data.MySqlClient
                 connection.HandleTimeout(tex);
                 return null;
             }
+            catch (ThreadAbortException ex)
+            {
+                connection.HandleException(Resources.ThreadAborted, ex);
+                throw;
+            }
             catch (MySqlException ex)
             {
                 connection.Reader = null;

=== modified file 'MySql.Data/Provider/Source/datareader.cs'
--- a/MySql.Data/Provider/Source/datareader.cs	2010-06-10 21:34:13 +0000
+++ b/MySql.Data/Provider/Source/datareader.cs	2010-06-21 17:43:00 +0000
@@ -27,6 +27,7 @@ using System.Data.SqlTypes;
 using System.Collections.Generic;
 using System.Globalization;
 using MySql.Data.MySqlClient.Properties;
+using System.Threading;
 
 namespace MySql.Data.MySqlClient
 {
@@ -879,6 +880,11 @@ namespace MySql.Data.MySqlClient
                 connection.HandleTimeout(tex);
                 return false; // unreached
             }
+            catch (ThreadAbortException ex)
+            {
+                connection.HandleException(Resources.ThreadAborted, ex);
+                throw;
+            }
             catch (MySqlException ex)
             {
                 if (ex.IsFatal)

=== modified file 'MySql.Data/Tests/Source/Threading.cs'
--- a/MySql.Data/Tests/Source/Threading.cs	2009-10-09 20:38:36 +0000
+++ b/MySql.Data/Tests/Source/Threading.cs	2010-06-21 17:43:00 +0000
@@ -27,6 +27,7 @@ using System.Collections;
 using System.Diagnostics;
 using System.Text;
 using System.Collections.Specialized;
+using MySql.Data.MySqlClient.Properties;
 
 namespace MySql.Data.MySqlClient.Tests
 {
@@ -120,6 +121,51 @@ namespace MySql.Data.MySqlClient.Tests
 				x++;
 			}
 		}
+
+        /// <summary>
+        /// Bug #54012  	MySql Connector/NET is not hardened to deal with ThreadAbortException
+        /// </summary>
+        private void HardenedThreadAbortExceptionWorker()
+        {
+            MySqlCommand cmd = new MySqlCommand();
+            try
+            {
+                using (MySqlConnection c = new MySqlConnection(GetConnectionString("root", "root", true)))
+                {
+                    c.Open();
+                    cmd.Connection = c;
+                    cmd.CommandText = "SELECT BENCHMARK(10000000000,ENCODE('hello','goodbye'))";
+                    cmd.ExecuteNonQuery();
+                    c.Close();
+                }
+            }
+            catch (MySqlException ex)
+            {
+                string thisMessage = ex.Message;
+                Assert.AreEqual(Resources.ThreadAborted, ex.Message);
+                Thread.ResetAbort();
+            }
+        }
+
+        [Test]
+        public void HardenedThreadAbortException()
+        {
+            try
+            {
+                Thread t = new Thread(new ThreadStart(HardenedThreadAbortExceptionWorker));
+                t.Name = "Execute Query";
+                t.Start();
+                Thread.Sleep(5000);
+                t.Abort();
+                while (t.ThreadState == System.Threading.ThreadState.AbortRequested)
+                    Thread.Sleep(5000);
+                t.Join();
+            }
+            catch
+            {
+                Assert.Fail("Test failed.");
+            }
+        }
 	}
 
 }

Attachment: [text/bzr-bundle] bzr/iggy@mysql.com-20100621174300-6l06c1uk6kkvp4ej.bundle
Thread
bzr commit into connector-net-6.2 branch (iggy:858) Bug#54012Iggy Galarza21 Jun