Skip to content

MySqlConnection.Dispose hangs if an exception occurs calling a stored function #299

@smfeest

Description

@smfeest

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.

  1. 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 ;
  1. 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");
            }
        }
    }
}
  1. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions