If an error occurs while calling a MySQL function through a command with a return value parameter, then any attempt to dispose the underlying connection results in the application hanging indefinitely.
Below is a minimal test case for reproducing the issue.
- Create a new database containing a function that always fails:
CREATE DATABASE functiontest;
CREATE USER functiontest@localhost;
GRANT ALL PRIVILEGES ON `functiontest`.* TO 'functiontest'@'localhost';
DELIMITER $$
CREATE FUNCTION FAILING_FUNCTION()
RETURNS INT
BEGIN
DECLARE v1 INT;
SELECT c1 FROM table_that_does_not_exist INTO v1;
RETURN v1;
END$$
DELIMITER ;
- Create a basic console application that attempts to call the function:
using System;
using System.Data;
using System.Data.Common;
using MySql.Data.MySqlClient;
namespace mysqlbug
{
class Program
{
static void Main(string[] args)
{
var connection = new MySqlConnection("Server=localhost;Uid=functiontest;Database=functiontest;");
try
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "FAILING_FUNCTION";
var returnParameter = command.CreateParameter();
returnParameter.DbType = DbType.Int32;
returnParameter.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnParameter);
command.ExecuteNonQuery();
}
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e);
}
finally
{
Console.WriteLine("BeforeDispose");
connection.Dispose();
Console.WriteLine("AfterDispose");
}
}
}
}
- Run the application. It always hangs on
connection.Dispose().
Similarly, if you wrap the command in a transaction:
// ...
connection.Open();
using (var transaction = connection.BeginTransaction())
using (var command = connection.CreateCommand())
{
// ...
The following exception occurs when the transaction is disposed:
Exception: MySql.Data.MySqlClient.MySqlException: There is already an open DataReader associated with this Connection which must be closed first.
at MySql.Data.Serialization.MySqlSession.StartQuerying(MySqlCommand command)
at MySql.Data.MySqlClient.CommandExecutors.TextCommandExecutor.<ExecuteReaderAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MySql.Data.MySqlClient.CommandExecutors.TextCommandExecutor.<ExecuteNonQueryAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
at MySql.Data.MySqlClient.MySqlTransaction.Dispose(Boolean disposing)
at mysqlbug.Program.Main(String[] args) in /Users/sfeest/Personal/git/mysqlbug/Program.cs:line 30
If an error occurs while calling a MySQL function through a command with a return value parameter, then any attempt to dispose the underlying connection results in the application hanging indefinitely.
Below is a minimal test case for reproducing the issue.
connection.Dispose().Similarly, if you wrap the command in a transaction:
The following exception occurs when the transaction is disposed: