Skip to content

Commit

Permalink
Work around server query attributes bug. Fixes #1106
Browse files Browse the repository at this point in the history
MySQL Server versions 8.0.23-8.0.25 contain bugs that prevent them from parsing attributes in the COM_STMT_EXECUTE packet. The new PARAMETER_COUNT_AVAILABLE flag is added in 8.0.26 to enable attributes to be sent. If we detect an older server (that advertises support for query attributes), we send an empty string parameter name, but omit the attributes.
  • Loading branch information
bgrainger committed Dec 23, 2021
1 parent 91a4111 commit 3c212dd
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 9 deletions.
20 changes: 12 additions & 8 deletions src/MySqlConnector/Core/SingleCommandPayloadCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,29 @@ private static void WritePreparedStatement(IMySqlCommand command, PreparedStatem

var attributes = command.RawAttributes;
var supportsQueryAttributes = command.Connection!.Session.SupportsQueryAttributes;

writer.Write(preparedStatement.StatementId);

// NOTE: documentation is not updated yet, but due to bugs in MySQL Server 8.0.23-8.0.25, the PARAMETER_COUNT_AVAILABLE (0x08)
// flag has to be set in the 'flags' block in order for query attributes to be sent with a prepared statement; we do not version-sniff the
// server but assume that it must support this flag
writer.Write((byte) (supportsQueryAttributes ? 8 : 0));
// flag has to be set in the 'flags' block in order for query attributes to be sent with a prepared statement.
var sendQueryAttributes = supportsQueryAttributes && command.Connection.Session.ServerVersion.Version is not { Major: 8, Minor: 0, Build: >= 23 and <= 25 };
writer.Write((byte) (sendQueryAttributes ? 8 : 0));
writer.Write(1);

var commandParameterCount = preparedStatement.Statement.ParameterNames?.Count ?? 0;
var attributeCount = attributes?.Count ?? 0;
if (supportsQueryAttributes)
if (sendQueryAttributes)
{
writer.WriteLengthEncodedInteger((uint) (commandParameterCount + attributeCount));
}
else if (attributeCount > 0)
else
{
Log.Warn("Session{0} has attributes for CommandId {1} but the server does not support them", command.Connection!.Session.Id, preparedStatement.StatementId);
attributeCount = 0;
if (supportsQueryAttributes && commandParameterCount > 0)
writer.WriteLengthEncodedInteger((uint) commandParameterCount);
if (attributeCount > 0)
{
Log.Warn("Session{0} has attributes for CommandId {1} but the server does not support them", command.Connection!.Session.Id, preparedStatement.StatementId);
attributeCount = 0;
}
}

if (commandParameterCount > 0 || attributeCount > 0)
Expand Down
2 changes: 1 addition & 1 deletion tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ with Connector/NET and that [known bugs have been fixed](https://mysqlconnector.

The tests require a MySQL server. The simplest way to run one is with [Docker](https://www.docker.com/community-edition):

docker run -d --rm --name mysqlconnector -e MYSQL_ROOT_PASSWORD=pass -p 3306:3306 mysql:8.0.23 --max-allowed-packet=96M --character-set-server=utf8mb4 --log-bin-trust-function-creators=1 --local-infile=1 --max-connections=250
docker run -d --rm --name mysqlconnector -e MYSQL_ROOT_PASSWORD=pass -p 3306:3306 mysql:8.0.27 --max-allowed-packet=96M --character-set-server=utf8mb4 --log-bin-trust-function-creators=1 --local-infile=1 --max-connections=250

Copy the file `SideBySide/config.json.example` to `SideBySide/config.json`, then edit
the `config.json` file in order to connect to your server. If you are using the Docker
Expand Down

0 comments on commit 3c212dd

Please sign in to comment.