Description:
If the same instance of a MySqlCommand object has an execute call made on it more than once with opentelemtery enabled ("connector-net" activity source has a listener set on it), the second execute call of the command causes an unhandled exception and the command execute call fails. Unhandled exception information: Object reference not set to an instance of an object. at MySql.Data.MySqlClient.MySqlConnection.set_Reader(MySqlDataReader value) in MySql.Data.MySqlClient\MySqlConnection.cs:line 63
To stop this exception, opentelemetery must be disabled, there cannot be any listeners set on the "connector-net" activity source.
When using prepared statements it's common to call an execute method on the same command instance more than once. This use case was how this issue was discovered.
How to repeat:
// Using the code below with the following Nuget packages will cause the exception to occur
// Nuget packages used:
// <PackageReference Include="MySql.Data" Version="9.0.0" />
// <PackageReference Include = "OpenTelemetry" Version = "1.9.0" />
// <PackageReference Include = "OpenTelemetry.Exporter.Console" Version = "1.9.0" />
using System.Data.Common;
using System.Data;
using OpenTelemetry;
using OpenTelemetry.Trace;
using MySql.Data.MySqlClient;
namespace TestAppExample
{
public class Program
{
public static void Main()
{
var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddConsoleExporter()
.AddSource("connector-net")
.Build();
DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", MySql.Data.MySqlClient.MySqlClientFactory.Instance);
RunPrepareStatement();
tracerProvider.Dispose();
}
static void RunPrepareStatement()
{
DbProviderFactory factory = DbProviderFactories.GetFactory("MySql.Data.MySqlClient");
string connectionString = "Server=localhost;Port=3306;Initial Catalog=dbo;User Id=test_user;Password=password;";
using MySqlConnection connection = new MySqlConnection(connectionString);
connection.Open();
string selectQuery = "SELECT * FROM BOOK WHERE Color=@val1";
using var command = new MySqlCommand(selectQuery, connection);
command.CommandType = CommandType.Text;
command.Connection = connection;
DbParameter color = command.CreateParameter();
color.ParameterName = "@val1";
command.Parameters.Add(color);
command.Prepare();
color.Value = "Black";
string results = string.Empty;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
results = results + $"name: {reader.GetString(1)} ";
}
}
// Run prepared command again with different parameter value
color.Value = "Red";
// Running command second time results in an unhandled exception
using (var reader = command.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
{
while (reader.Read())
{
results = results + $"name: {reader.GetString(1)}";
}
}
}
}
}
Suggested fix:
If a command instance is run more than once do not add another sql attribute to the command. A `traceparent` attribute is being added to the command each time an activity is started.
Support configuration for whether or not the `traceparent` is added to the sql attributes as part of the start activity.