diff --git a/sqlx-core/src/mysql/connection/establish.rs b/sqlx-core/src/mysql/connection/establish.rs index ce5e5a31..0127f2bd 100644 --- a/sqlx-core/src/mysql/connection/establish.rs +++ b/sqlx-core/src/mysql/connection/establish.rs @@ -2,7 +2,9 @@ use bytes::Bytes; use crate::common::StatementCache; use crate::error::Error; -use crate::mysql::connection::{tls, MySqlStream, COLLATE_UTF8MB4_UNICODE_CI, MAX_PACKET_SIZE}; +use crate::mysql::connection::{ + tls, MySqlStream, COLLATE_UTF8MB4_UNICODE_CI, COLLATE_UTF8_UNICODE_CI, MAX_PACKET_SIZE, +}; use crate::mysql::protocol::connect::{ AuthSwitchRequest, AuthSwitchResponse, Handshake, HandshakeResponse, }; @@ -22,6 +24,35 @@ impl MySqlConnection { let mut plugin = handshake.auth_plugin; let mut nonce = handshake.auth_plugin_data; + // FIXME: server version parse is a bit ugly + // expecting MAJOR.MINOR.PATCH + + let mut server_version = handshake.server_version.split('.'); + + let server_version_major: u16 = server_version + .next() + .unwrap_or_default() + .parse() + .unwrap_or(0); + + let server_version_minor: u16 = server_version + .next() + .unwrap_or_default() + .parse() + .unwrap_or(0); + + let server_version_patch: u16 = server_version + .next() + .unwrap_or_default() + .parse() + .unwrap_or(0); + + stream.server_version = ( + server_version_major, + server_version_minor, + server_version_patch, + ); + stream.capabilities &= handshake.server_capabilities; stream.capabilities |= Capabilities::PROTOCOL_41; @@ -39,8 +70,14 @@ impl MySqlConnection { None }; + let char_set = if stream.server_version >= (5, 5, 3) { + COLLATE_UTF8MB4_UNICODE_CI + } else { + COLLATE_UTF8_UNICODE_CI + }; + stream.write_packet(HandshakeResponse { - char_set: COLLATE_UTF8MB4_UNICODE_CI, + char_set, max_packet_size: MAX_PACKET_SIZE, username: &options.username, database: options.database.as_deref(), diff --git a/sqlx-core/src/mysql/connection/mod.rs b/sqlx-core/src/mysql/connection/mod.rs index e6706d6a..d4314361 100644 --- a/sqlx-core/src/mysql/connection/mod.rs +++ b/sqlx-core/src/mysql/connection/mod.rs @@ -22,7 +22,8 @@ mod tls; use crate::transaction::Transaction; pub(crate) use stream::{Busy, MySqlStream}; -const COLLATE_UTF8MB4_UNICODE_CI: u8 = 224; +pub(crate) const COLLATE_UTF8_UNICODE_CI: u8 = 192; +pub(crate) const COLLATE_UTF8MB4_UNICODE_CI: u8 = 224; const MAX_PACKET_SIZE: u32 = 1024; diff --git a/sqlx-core/src/mysql/connection/stream.rs b/sqlx-core/src/mysql/connection/stream.rs index ed7106a5..59bfbee1 100644 --- a/sqlx-core/src/mysql/connection/stream.rs +++ b/sqlx-core/src/mysql/connection/stream.rs @@ -12,6 +12,7 @@ use crate::net::{MaybeTlsStream, Socket}; pub struct MySqlStream { stream: BufStream>, + pub(crate) server_version: (u16, u16, u16), pub(super) capabilities: Capabilities, pub(crate) sequence_id: u8, pub(crate) busy: Busy, @@ -55,6 +56,7 @@ impl MySqlStream { Ok(Self { busy: Busy::NotBusy, capabilities, + server_version: (0, 0, 0), sequence_id: 0, stream: BufStream::new(MaybeTlsStream::Raw(socket)), }) diff --git a/sqlx-core/src/mysql/options/connect.rs b/sqlx-core/src/mysql/options/connect.rs index 69029e45..05111b27 100644 --- a/sqlx-core/src/mysql/options/connect.rs +++ b/sqlx-core/src/mysql/options/connect.rs @@ -39,11 +39,19 @@ impl ConnectOptions for MySqlConnectOptions { // https://mathiasbynens.be/notes/mysql-utf8mb4 - conn.execute(concat!( - r#"SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION')),"#, - r#"time_zone='+00:00',"#, - r#"NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;"#, - )).await?; + let mut options = String::new(); + options.push_str(r#"SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION')),"#); + options.push_str(r#"time_zone='+00:00',"#); + + let char_set = if conn.stream.server_version >= (5, 5, 3) { + "utf8mb4" + } else { + "utf8" + }; + + options.push_str(&format!(r#"NAMES {0} COLLATE {0}_unicode_ci;"#, char_set)); + + conn.execute(&*options).await?; Ok(conn) }) diff --git a/sqlx-core/src/mysql/types/str.rs b/sqlx-core/src/mysql/types/str.rs index c88c347a..d747df08 100644 --- a/sqlx-core/src/mysql/types/str.rs +++ b/sqlx-core/src/mysql/types/str.rs @@ -1,6 +1,7 @@ use crate::decode::Decode; use crate::encode::{Encode, IsNull}; use crate::error::BoxDynError; +use crate::mysql::connection::{COLLATE_UTF8MB4_UNICODE_CI, COLLATE_UTF8_UNICODE_CI}; use crate::mysql::io::MySqlBufMutExt; use crate::mysql::protocol::text::{ColumnFlags, ColumnType}; use crate::mysql::{MySql, MySqlTypeInfo, MySqlValueRef}; @@ -26,7 +27,8 @@ impl Type for str { | ColumnType::String | ColumnType::VarString | ColumnType::Enum - ) && ty.char_set == 224 + ) && (ty.char_set == COLLATE_UTF8MB4_UNICODE_CI.into() + || ty.char_set == COLLATE_UTF8_UNICODE_CI.into()) } }