Skip to content

Unexpected treat MySQL BINARY(size) type as String in AnyRow #4132

@Kr328

Description

@Kr328

I have found these related issues/pull requests

During the conversion of MySqlRow to AnyRow, sqlx unexpectedly treated the binary(size) type as a string, which caused the utf8 decoding to fail.

Description

In code:

sqlx/sqlx-mysql/src/any.rs

Lines 152 to 179 in e8384f2

impl<'a> TryFrom<&'a MySqlTypeInfo> for AnyTypeInfo {
type Error = sqlx_core::Error;
fn try_from(type_info: &'a MySqlTypeInfo) -> Result<Self, Self::Error> {
Ok(AnyTypeInfo {
kind: match &type_info.r#type {
ColumnType::Null => AnyTypeInfoKind::Null,
ColumnType::Short => AnyTypeInfoKind::SmallInt,
ColumnType::Long => AnyTypeInfoKind::Integer,
ColumnType::LongLong => AnyTypeInfoKind::BigInt,
ColumnType::Float => AnyTypeInfoKind::Real,
ColumnType::Double => AnyTypeInfoKind::Double,
ColumnType::Blob
| ColumnType::TinyBlob
| ColumnType::MediumBlob
| ColumnType::LongBlob => AnyTypeInfoKind::Blob,
ColumnType::String | ColumnType::VarString | ColumnType::VarChar => {
AnyTypeInfoKind::Text
}
_ => {
return Err(sqlx_core::Error::AnyDriverError(
format!("Any driver does not support MySql type {type_info:?}").into(),
))
}
},
})
}
}

MySqlTypeInfo has type = ColumnType::String and flags = 4227, this value should be treated as binary data, but it actual be treated as string.

After apply this patch, everything work fine:

diff --git a/sqlx-mysql/src/any.rs b/sqlx-mysql/src/any.rs
index 19b3a6f2..a247499e 100644
--- a/sqlx-mysql/src/any.rs
+++ b/sqlx-mysql/src/any.rs
@@ -1,4 +1,4 @@
-use crate::protocol::text::ColumnType;
+use crate::protocol::text::{ColumnFlags, ColumnType};
 use crate::{
     MySql, MySqlColumn, MySqlConnectOptions, MySqlConnection, MySqlQueryResult, MySqlRow,
     MySqlTransactionManager, MySqlTypeInfo,
@@ -173,7 +173,11 @@ impl<'a> TryFrom<&'a MySqlTypeInfo> for AnyTypeInfo {
                 | ColumnType::MediumBlob
                 | ColumnType::LongBlob => AnyTypeInfoKind::Blob,
                 ColumnType::String | ColumnType::VarString | ColumnType::VarChar => {
-                    AnyTypeInfoKind::Text
+                    if type_info.flags.contains(ColumnFlags::BINARY) {
+                        AnyTypeInfoKind::Blob
+                    } else {
+                        AnyTypeInfoKind::Text
+                    }
                 }
                 _ => {
                     return Err(sqlx_core::Error::AnyDriverError(

Reproduction steps

Run follow code:

#[tokio::main]
async fn main() {
    sqlx::any::install_default_drivers();

    let pool = sqlx::AnyPool::connect(env!("DATABASE_URL")).await.unwrap();

    sqlx::query("CREATE TABLE IF NOT EXISTS `test`(id BINARY(16) PRIMARY KEY)")
        .execute(&pool)
        .await
        .unwrap();

    sqlx::query("INSERT INTO `test`(id) VALUES(UNHEX(REPLACE(UUID(), '-', '')))")
        .execute(&pool)
        .await
        .unwrap();

    sqlx::query("SELECT * FROM `test`").fetch_all(&pool).await.unwrap(); // panic: called `Result::unwrap()` on an `Err` value: Decode(Utf8Error { valid_up_to: 4, error_len: Some(1) })
}

It panic with Utf8Error:

thread 'main' (298286) panicked at src/main.rs:17:64:
called `Result::unwrap()` on an `Err` value: Decode(Utf8Error { valid_up_to: 4, error_len: Some(1) })

SQLx version

0.8.6

Enabled SQLx features

["runtime-tokio", "mysql", "macros", "any"]

Database server and version

/usr/sbin/mysqld Ver 9.5.0 for Linux on x86_64 (MySQL Community Server - GPL)

Operating system

Linux 6.18.2-arch2-1 #1 SMP PREEMPT_DYNAMIC Thu, 18 Dec 2025 18:00:18 +0000 x86_64 GNU/Linux

Rust version

rustc 1.91.1 (ed61e7d7e 2025-11-07)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions