breaking(mysql): assume all non-binary collations compatible with str (#3924)

cc https://github.com/launchbadge/sqlx/pull/3400#issuecomment-3041035104

comment in `sqlx-mysql/src/collation.rs` for explanation

fixes #3200
fixes #3387
fixes #3390
fixes #3409
This commit is contained in:
Austin Bonander 2025-07-08 00:39:46 -07:00 committed by GitHub
parent 469f22788e
commit a3aa942a78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 248 additions and 1029 deletions

View File

@ -419,7 +419,7 @@ jobs:
runs-on: ubuntu-24.04
strategy:
matrix:
mariadb: [ verylatest, 11_4, 10_11, 10_4 ]
mariadb: [ verylatest, 11_8, 11_4, 10_11, 10_6 ]
runtime: [ async-std, tokio ]
tls: [ native-tls, rustls-aws-lc-rs, rustls-ring, none ]
needs: check
@ -446,7 +446,7 @@ jobs:
env:
DATABASE_URL: mysql://root:password@localhost:3306/sqlx
SQLX_OFFLINE_DIR: .sqlx
RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }}
RUSTFLAGS: --cfg mariadb="${{ matrix.mariadb }}"
# Run the `test-attr` test again to cover cleanup.
- run: >
@ -457,7 +457,7 @@ jobs:
env:
DATABASE_URL: mysql://root:password@localhost:3306/sqlx
SQLX_OFFLINE_DIR: .sqlx
RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }}
RUSTFLAGS: --cfg mariadb="${{ matrix.mariadb }}"
# Remove test artifacts
- run: cargo clean -p sqlx
@ -471,7 +471,7 @@ jobs:
env:
SQLX_OFFLINE: true
SQLX_OFFLINE_DIR: .sqlx
RUSTFLAGS: -D warnings --cfg mariadb_${{ matrix.mariadb }}
RUSTFLAGS: -D warnings --cfg mariadb="${{ matrix.mariadb }}"
# Test macros in offline mode (still needs DATABASE_URL to run)
- run: >
@ -483,7 +483,7 @@ jobs:
DATABASE_URL: mysql://root:password@localhost:3306/sqlx
SQLX_OFFLINE: true
SQLX_OFFLINE_DIR: .sqlx
RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }}
RUSTFLAGS: --cfg mariadb="${{ matrix.mariadb }}"
# client SSL authentication
@ -500,4 +500,4 @@ jobs:
--features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}
env:
DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fcerts%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt
RUSTFLAGS: --cfg mariadb_${{ matrix.mariadb }}
RUSTFLAGS: --cfg mariadb="${{ matrix.mariadb }}"

12
Cargo.lock generated
View File

@ -772,9 +772,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.26"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
dependencies = [
"clap_builder",
"clap_derive",
@ -782,9 +782,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.26"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
dependencies = [
"anstream",
"anstyle",
@ -804,9 +804,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.24"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
dependencies = [
"heck 0.5.0",
"proc-macro2",

View File

@ -210,6 +210,9 @@ cast_sign_loss = 'deny'
# See `clippy.toml`
disallowed_methods = 'deny'
[lints.rust]
unexpected_cfgs = { level = 'warn', check-cfg = ['cfg(mariadb, values(any()))'] }
#
# Any
#

View File

@ -240,11 +240,11 @@ impl RawSql {
///
/// Otherwise, you might want to add `LIMIT 1` to your query.
#[inline]
pub async fn fetch_optional<'e, E, DB>(self, executor: E) -> crate::Result<DB::Row>
pub async fn fetch_optional<'e, E, DB>(self, executor: E) -> crate::Result<Option<DB::Row>>
where
DB: Database,
E: Executor<'e, Database = DB>,
{
executor.fetch_one(self).await
executor.fetch_optional(self).await
}
}

View File

@ -1,900 +1,49 @@
use crate::error::Error;
use std::str::FromStr;
// One of several questionable design decisions in MySQL is the choice to conflate
// *how stored data is sorted* with the character encoding used over the wire.
//
// The documentation for `Protocol::HandshakeResponse41` implies that
// the lower 8 bits of the collation ID may be used to uniquely identify the character set:
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_response.html
//
// However, this isn't at _all_ true in practice. Collation IDs are assigned without any apparent
// rhyme or reason, mostly just sequential with unexplained gaps. Masking the collation ID with 0xFF
// doesn't actually tell you anything meaningful, except obviously for collation IDs under 256
// which just gives you the same collation ID again.
//
// Hanlon's razor would suggest they just forgot that they told clients they could do this.
// Occam's razor suggests no one ever bothers to set the connection charset/collation this way,
// and they all just default to `latin1_swedish_ci` (8), `utf8mb4_general_ci` (45),
// or `utf8mb4_0900_ai_ci` (255).
//
// This would seem to mean that if we want to be *sure* of the character encoding of a given column,
// we have to reference the _full_ catalog of collations. Because new ones are added occasionally,
// we can't just assume a collation we don't recognize is UTF-8 as that's not always the case.
//
// This is especially true when we include MariaDB because they've started creating
// their *own* collations, and even character sets, separately from MySQL.
//
// Awesome, right?
//
// However, as long as `character_set_client` and `character_set_results` are set correctly,
// we can assume that any non-binary collation is a valid string, because the server will transcode.
// As it turns out, the collation specified in the `Protocol::ColumnDefinition`
// is *purely* informational. It has no bearing on what's sent over the wire except for `binary` (63),
// which is never transcoded.
//
// So at the end of the day, none of this matters anyway! To know if a column is a string or not,
// we merely need to check if it's not `binary` (63). If the protocol was just a *bit*
// better documented, it would have saved me literally six hours spent figuring this out.
//
// Thanks, MySQL.
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub(crate) enum CharSet {
armscii8,
ascii,
big5,
binary,
cp1250,
cp1251,
cp1256,
cp1257,
cp850,
cp852,
cp866,
cp932,
dec8,
eucjpms,
euckr,
gb18030,
gb2312,
gbk,
geostd8,
greek,
hebrew,
hp8,
keybcs2,
koi8r,
koi8u,
latin1,
latin2,
latin5,
latin7,
macce,
macroman,
sjis,
swe7,
tis620,
ucs2,
ujis,
utf16,
utf16le,
utf32,
utf8,
utf8mb4,
}
impl CharSet {
pub(crate) fn as_str(&self) -> &'static str {
match self {
CharSet::armscii8 => "armscii8",
CharSet::ascii => "ascii",
CharSet::big5 => "big5",
CharSet::binary => "binary",
CharSet::cp1250 => "cp1250",
CharSet::cp1251 => "cp1251",
CharSet::cp1256 => "cp1256",
CharSet::cp1257 => "cp1257",
CharSet::cp850 => "cp850",
CharSet::cp852 => "cp852",
CharSet::cp866 => "cp866",
CharSet::cp932 => "cp932",
CharSet::dec8 => "dec8",
CharSet::eucjpms => "eucjpms",
CharSet::euckr => "euckr",
CharSet::gb18030 => "gb18030",
CharSet::gb2312 => "gb2312",
CharSet::gbk => "gbk",
CharSet::geostd8 => "geostd8",
CharSet::greek => "greek",
CharSet::hebrew => "hebrew",
CharSet::hp8 => "hp8",
CharSet::keybcs2 => "keybcs2",
CharSet::koi8r => "koi8r",
CharSet::koi8u => "koi8u",
CharSet::latin1 => "latin1",
CharSet::latin2 => "latin2",
CharSet::latin5 => "latin5",
CharSet::latin7 => "latin7",
CharSet::macce => "macce",
CharSet::macroman => "macroman",
CharSet::sjis => "sjis",
CharSet::swe7 => "swe7",
CharSet::tis620 => "tis620",
CharSet::ucs2 => "ucs2",
CharSet::ujis => "ujis",
CharSet::utf16 => "utf16",
CharSet::utf16le => "utf16le",
CharSet::utf32 => "utf32",
CharSet::utf8 => "utf8",
CharSet::utf8mb4 => "utf8mb4",
}
}
pub(crate) fn default_collation(&self) -> Collation {
match self {
CharSet::armscii8 => Collation::armscii8_general_ci,
CharSet::ascii => Collation::ascii_general_ci,
CharSet::big5 => Collation::big5_chinese_ci,
CharSet::binary => Collation::binary,
CharSet::cp1250 => Collation::cp1250_general_ci,
CharSet::cp1251 => Collation::cp1251_general_ci,
CharSet::cp1256 => Collation::cp1256_general_ci,
CharSet::cp1257 => Collation::cp1257_general_ci,
CharSet::cp850 => Collation::cp850_general_ci,
CharSet::cp852 => Collation::cp852_general_ci,
CharSet::cp866 => Collation::cp866_general_ci,
CharSet::cp932 => Collation::cp932_japanese_ci,
CharSet::dec8 => Collation::dec8_swedish_ci,
CharSet::eucjpms => Collation::eucjpms_japanese_ci,
CharSet::euckr => Collation::euckr_korean_ci,
CharSet::gb18030 => Collation::gb18030_chinese_ci,
CharSet::gb2312 => Collation::gb2312_chinese_ci,
CharSet::gbk => Collation::gbk_chinese_ci,
CharSet::geostd8 => Collation::geostd8_general_ci,
CharSet::greek => Collation::greek_general_ci,
CharSet::hebrew => Collation::hebrew_general_ci,
CharSet::hp8 => Collation::hp8_english_ci,
CharSet::keybcs2 => Collation::keybcs2_general_ci,
CharSet::koi8r => Collation::koi8r_general_ci,
CharSet::koi8u => Collation::koi8u_general_ci,
CharSet::latin1 => Collation::latin1_swedish_ci,
CharSet::latin2 => Collation::latin2_general_ci,
CharSet::latin5 => Collation::latin5_turkish_ci,
CharSet::latin7 => Collation::latin7_general_ci,
CharSet::macce => Collation::macce_general_ci,
CharSet::macroman => Collation::macroman_general_ci,
CharSet::sjis => Collation::sjis_japanese_ci,
CharSet::swe7 => Collation::swe7_swedish_ci,
CharSet::tis620 => Collation::tis620_thai_ci,
CharSet::ucs2 => Collation::ucs2_general_ci,
CharSet::ujis => Collation::ujis_japanese_ci,
CharSet::utf16 => Collation::utf16_general_ci,
CharSet::utf16le => Collation::utf16le_general_ci,
CharSet::utf32 => Collation::utf32_general_ci,
CharSet::utf8 => Collation::utf8_unicode_ci,
CharSet::utf8mb4 => Collation::utf8mb4_unicode_ci,
}
}
}
impl FromStr for CharSet {
type Err = Error;
fn from_str(char_set: &str) -> Result<Self, Self::Err> {
Ok(match char_set {
"armscii8" => CharSet::armscii8,
"ascii" => CharSet::ascii,
"big5" => CharSet::big5,
"binary" => CharSet::binary,
"cp1250" => CharSet::cp1250,
"cp1251" => CharSet::cp1251,
"cp1256" => CharSet::cp1256,
"cp1257" => CharSet::cp1257,
"cp850" => CharSet::cp850,
"cp852" => CharSet::cp852,
"cp866" => CharSet::cp866,
"cp932" => CharSet::cp932,
"dec8" => CharSet::dec8,
"eucjpms" => CharSet::eucjpms,
"euckr" => CharSet::euckr,
"gb18030" => CharSet::gb18030,
"gb2312" => CharSet::gb2312,
"gbk" => CharSet::gbk,
"geostd8" => CharSet::geostd8,
"greek" => CharSet::greek,
"hebrew" => CharSet::hebrew,
"hp8" => CharSet::hp8,
"keybcs2" => CharSet::keybcs2,
"koi8r" => CharSet::koi8r,
"koi8u" => CharSet::koi8u,
"latin1" => CharSet::latin1,
"latin2" => CharSet::latin2,
"latin5" => CharSet::latin5,
"latin7" => CharSet::latin7,
"macce" => CharSet::macce,
"macroman" => CharSet::macroman,
"sjis" => CharSet::sjis,
"swe7" => CharSet::swe7,
"tis620" => CharSet::tis620,
"ucs2" => CharSet::ucs2,
"ujis" => CharSet::ujis,
"utf16" => CharSet::utf16,
"utf16le" => CharSet::utf16le,
"utf32" => CharSet::utf32,
"utf8" => CharSet::utf8,
"utf8mb4" => CharSet::utf8mb4,
_ => {
return Err(Error::Configuration(
format!("unsupported MySQL charset: {char_set}").into(),
));
}
})
}
}
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(u8)]
pub(crate) enum Collation {
armscii8_bin = 64,
armscii8_general_ci = 32,
ascii_bin = 65,
ascii_general_ci = 11,
big5_bin = 84,
big5_chinese_ci = 1,
binary = 63,
cp1250_bin = 66,
cp1250_croatian_ci = 44,
cp1250_czech_cs = 34,
cp1250_general_ci = 26,
cp1250_polish_ci = 99,
cp1251_bin = 50,
cp1251_bulgarian_ci = 14,
cp1251_general_ci = 51,
cp1251_general_cs = 52,
cp1251_ukrainian_ci = 23,
cp1256_bin = 67,
cp1256_general_ci = 57,
cp1257_bin = 58,
cp1257_general_ci = 59,
cp1257_lithuanian_ci = 29,
cp850_bin = 80,
cp850_general_ci = 4,
cp852_bin = 81,
cp852_general_ci = 40,
cp866_bin = 68,
cp866_general_ci = 36,
cp932_bin = 96,
cp932_japanese_ci = 95,
dec8_bin = 69,
dec8_swedish_ci = 3,
eucjpms_bin = 98,
eucjpms_japanese_ci = 97,
euckr_bin = 85,
euckr_korean_ci = 19,
gb18030_bin = 249,
gb18030_chinese_ci = 248,
gb18030_unicode_520_ci = 250,
gb2312_bin = 86,
gb2312_chinese_ci = 24,
gbk_bin = 87,
gbk_chinese_ci = 28,
geostd8_bin = 93,
geostd8_general_ci = 92,
greek_bin = 70,
greek_general_ci = 25,
hebrew_bin = 71,
hebrew_general_ci = 16,
hp8_bin = 72,
hp8_english_ci = 6,
keybcs2_bin = 73,
keybcs2_general_ci = 37,
koi8r_bin = 74,
koi8r_general_ci = 7,
koi8u_bin = 75,
koi8u_general_ci = 22,
latin1_bin = 47,
latin1_danish_ci = 15,
latin1_general_ci = 48,
latin1_general_cs = 49,
latin1_german1_ci = 5,
latin1_german2_ci = 31,
latin1_spanish_ci = 94,
latin1_swedish_ci = 8,
latin2_bin = 77,
latin2_croatian_ci = 27,
latin2_czech_cs = 2,
latin2_general_ci = 9,
latin2_hungarian_ci = 21,
latin5_bin = 78,
latin5_turkish_ci = 30,
latin7_bin = 79,
latin7_estonian_cs = 20,
latin7_general_ci = 41,
latin7_general_cs = 42,
macce_bin = 43,
macce_general_ci = 38,
macroman_bin = 53,
macroman_general_ci = 39,
sjis_bin = 88,
sjis_japanese_ci = 13,
swe7_bin = 82,
swe7_swedish_ci = 10,
tis620_bin = 89,
tis620_thai_ci = 18,
ucs2_bin = 90,
ucs2_croatian_ci = 149,
ucs2_czech_ci = 138,
ucs2_danish_ci = 139,
ucs2_esperanto_ci = 145,
ucs2_estonian_ci = 134,
ucs2_general_ci = 35,
ucs2_general_mysql500_ci = 159,
ucs2_german2_ci = 148,
ucs2_hungarian_ci = 146,
ucs2_icelandic_ci = 129,
ucs2_latvian_ci = 130,
ucs2_lithuanian_ci = 140,
ucs2_persian_ci = 144,
ucs2_polish_ci = 133,
ucs2_roman_ci = 143,
ucs2_romanian_ci = 131,
ucs2_sinhala_ci = 147,
ucs2_slovak_ci = 141,
ucs2_slovenian_ci = 132,
ucs2_spanish_ci = 135,
ucs2_spanish2_ci = 142,
ucs2_swedish_ci = 136,
ucs2_turkish_ci = 137,
ucs2_unicode_520_ci = 150,
ucs2_unicode_ci = 128,
ucs2_vietnamese_ci = 151,
ujis_bin = 91,
ujis_japanese_ci = 12,
utf16_bin = 55,
utf16_croatian_ci = 122,
utf16_czech_ci = 111,
utf16_danish_ci = 112,
utf16_esperanto_ci = 118,
utf16_estonian_ci = 107,
utf16_general_ci = 54,
utf16_german2_ci = 121,
utf16_hungarian_ci = 119,
utf16_icelandic_ci = 102,
utf16_latvian_ci = 103,
utf16_lithuanian_ci = 113,
utf16_persian_ci = 117,
utf16_polish_ci = 106,
utf16_roman_ci = 116,
utf16_romanian_ci = 104,
utf16_sinhala_ci = 120,
utf16_slovak_ci = 114,
utf16_slovenian_ci = 105,
utf16_spanish_ci = 108,
utf16_spanish2_ci = 115,
utf16_swedish_ci = 109,
utf16_turkish_ci = 110,
utf16_unicode_520_ci = 123,
utf16_unicode_ci = 101,
utf16_vietnamese_ci = 124,
utf16le_bin = 62,
utf16le_general_ci = 56,
utf32_bin = 61,
utf32_croatian_ci = 181,
utf32_czech_ci = 170,
utf32_danish_ci = 171,
utf32_esperanto_ci = 177,
utf32_estonian_ci = 166,
utf32_general_ci = 60,
utf32_german2_ci = 180,
utf32_hungarian_ci = 178,
utf32_icelandic_ci = 161,
utf32_latvian_ci = 162,
utf32_lithuanian_ci = 172,
utf32_persian_ci = 176,
utf32_polish_ci = 165,
utf32_roman_ci = 175,
utf32_romanian_ci = 163,
utf32_sinhala_ci = 179,
utf32_slovak_ci = 173,
utf32_slovenian_ci = 164,
utf32_spanish_ci = 167,
utf32_spanish2_ci = 174,
utf32_swedish_ci = 168,
utf32_turkish_ci = 169,
utf32_unicode_520_ci = 182,
utf32_unicode_ci = 160,
utf32_vietnamese_ci = 183,
utf8_bin = 83,
utf8_croatian_ci = 213,
utf8_czech_ci = 202,
utf8_danish_ci = 203,
utf8_esperanto_ci = 209,
utf8_estonian_ci = 198,
utf8_general_ci = 33,
utf8_general_mysql500_ci = 223,
utf8_german2_ci = 212,
utf8_hungarian_ci = 210,
utf8_icelandic_ci = 193,
utf8_latvian_ci = 194,
utf8_lithuanian_ci = 204,
utf8_persian_ci = 208,
utf8_polish_ci = 197,
utf8_roman_ci = 207,
utf8_romanian_ci = 195,
utf8_sinhala_ci = 211,
utf8_slovak_ci = 205,
utf8_slovenian_ci = 196,
utf8_spanish_ci = 199,
utf8_spanish2_ci = 206,
utf8_swedish_ci = 200,
utf8_tolower_ci = 76,
utf8_turkish_ci = 201,
utf8_unicode_520_ci = 214,
utf8_unicode_ci = 192,
utf8_vietnamese_ci = 215,
utf8mb4_0900_ai_ci = 255,
utf8mb4_bin = 46,
utf8mb4_croatian_ci = 245,
utf8mb4_czech_ci = 234,
utf8mb4_danish_ci = 235,
utf8mb4_esperanto_ci = 241,
utf8mb4_estonian_ci = 230,
utf8mb4_general_ci = 45,
utf8mb4_german2_ci = 244,
utf8mb4_hungarian_ci = 242,
utf8mb4_icelandic_ci = 225,
utf8mb4_latvian_ci = 226,
utf8mb4_lithuanian_ci = 236,
utf8mb4_persian_ci = 240,
utf8mb4_polish_ci = 229,
utf8mb4_roman_ci = 239,
utf8mb4_romanian_ci = 227,
utf8mb4_sinhala_ci = 243,
utf8mb4_slovak_ci = 237,
utf8mb4_slovenian_ci = 228,
utf8mb4_spanish_ci = 231,
utf8mb4_spanish2_ci = 238,
utf8mb4_swedish_ci = 232,
utf8mb4_turkish_ci = 233,
utf8mb4_unicode_520_ci = 246,
utf8mb4_unicode_ci = 224,
utf8mb4_vietnamese_ci = 247,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "offline", derive(serde::Deserialize, serde::Serialize))]
pub struct Collation(pub u16);
impl Collation {
pub(crate) fn as_str(&self) -> &'static str {
match self {
Collation::armscii8_bin => "armscii8_bin",
Collation::armscii8_general_ci => "armscii8_general_ci",
Collation::ascii_bin => "ascii_bin",
Collation::ascii_general_ci => "ascii_general_ci",
Collation::big5_bin => "big5_bin",
Collation::big5_chinese_ci => "big5_chinese_ci",
Collation::binary => "binary",
Collation::cp1250_bin => "cp1250_bin",
Collation::cp1250_croatian_ci => "cp1250_croatian_ci",
Collation::cp1250_czech_cs => "cp1250_czech_cs",
Collation::cp1250_general_ci => "cp1250_general_ci",
Collation::cp1250_polish_ci => "cp1250_polish_ci",
Collation::cp1251_bin => "cp1251_bin",
Collation::cp1251_bulgarian_ci => "cp1251_bulgarian_ci",
Collation::cp1251_general_ci => "cp1251_general_ci",
Collation::cp1251_general_cs => "cp1251_general_cs",
Collation::cp1251_ukrainian_ci => "cp1251_ukrainian_ci",
Collation::cp1256_bin => "cp1256_bin",
Collation::cp1256_general_ci => "cp1256_general_ci",
Collation::cp1257_bin => "cp1257_bin",
Collation::cp1257_general_ci => "cp1257_general_ci",
Collation::cp1257_lithuanian_ci => "cp1257_lithuanian_ci",
Collation::cp850_bin => "cp850_bin",
Collation::cp850_general_ci => "cp850_general_ci",
Collation::cp852_bin => "cp852_bin",
Collation::cp852_general_ci => "cp852_general_ci",
Collation::cp866_bin => "cp866_bin",
Collation::cp866_general_ci => "cp866_general_ci",
Collation::cp932_bin => "cp932_bin",
Collation::cp932_japanese_ci => "cp932_japanese_ci",
Collation::dec8_bin => "dec8_bin",
Collation::dec8_swedish_ci => "dec8_swedish_ci",
Collation::eucjpms_bin => "eucjpms_bin",
Collation::eucjpms_japanese_ci => "eucjpms_japanese_ci",
Collation::euckr_bin => "euckr_bin",
Collation::euckr_korean_ci => "euckr_korean_ci",
Collation::gb18030_bin => "gb18030_bin",
Collation::gb18030_chinese_ci => "gb18030_chinese_ci",
Collation::gb18030_unicode_520_ci => "gb18030_unicode_520_ci",
Collation::gb2312_bin => "gb2312_bin",
Collation::gb2312_chinese_ci => "gb2312_chinese_ci",
Collation::gbk_bin => "gbk_bin",
Collation::gbk_chinese_ci => "gbk_chinese_ci",
Collation::geostd8_bin => "geostd8_bin",
Collation::geostd8_general_ci => "geostd8_general_ci",
Collation::greek_bin => "greek_bin",
Collation::greek_general_ci => "greek_general_ci",
Collation::hebrew_bin => "hebrew_bin",
Collation::hebrew_general_ci => "hebrew_general_ci",
Collation::hp8_bin => "hp8_bin",
Collation::hp8_english_ci => "hp8_english_ci",
Collation::keybcs2_bin => "keybcs2_bin",
Collation::keybcs2_general_ci => "keybcs2_general_ci",
Collation::koi8r_bin => "koi8r_bin",
Collation::koi8r_general_ci => "koi8r_general_ci",
Collation::koi8u_bin => "koi8u_bin",
Collation::koi8u_general_ci => "koi8u_general_ci",
Collation::latin1_bin => "latin1_bin",
Collation::latin1_danish_ci => "latin1_danish_ci",
Collation::latin1_general_ci => "latin1_general_ci",
Collation::latin1_general_cs => "latin1_general_cs",
Collation::latin1_german1_ci => "latin1_german1_ci",
Collation::latin1_german2_ci => "latin1_german2_ci",
Collation::latin1_spanish_ci => "latin1_spanish_ci",
Collation::latin1_swedish_ci => "latin1_swedish_ci",
Collation::latin2_bin => "latin2_bin",
Collation::latin2_croatian_ci => "latin2_croatian_ci",
Collation::latin2_czech_cs => "latin2_czech_cs",
Collation::latin2_general_ci => "latin2_general_ci",
Collation::latin2_hungarian_ci => "latin2_hungarian_ci",
Collation::latin5_bin => "latin5_bin",
Collation::latin5_turkish_ci => "latin5_turkish_ci",
Collation::latin7_bin => "latin7_bin",
Collation::latin7_estonian_cs => "latin7_estonian_cs",
Collation::latin7_general_ci => "latin7_general_ci",
Collation::latin7_general_cs => "latin7_general_cs",
Collation::macce_bin => "macce_bin",
Collation::macce_general_ci => "macce_general_ci",
Collation::macroman_bin => "macroman_bin",
Collation::macroman_general_ci => "macroman_general_ci",
Collation::sjis_bin => "sjis_bin",
Collation::sjis_japanese_ci => "sjis_japanese_ci",
Collation::swe7_bin => "swe7_bin",
Collation::swe7_swedish_ci => "swe7_swedish_ci",
Collation::tis620_bin => "tis620_bin",
Collation::tis620_thai_ci => "tis620_thai_ci",
Collation::ucs2_bin => "ucs2_bin",
Collation::ucs2_croatian_ci => "ucs2_croatian_ci",
Collation::ucs2_czech_ci => "ucs2_czech_ci",
Collation::ucs2_danish_ci => "ucs2_danish_ci",
Collation::ucs2_esperanto_ci => "ucs2_esperanto_ci",
Collation::ucs2_estonian_ci => "ucs2_estonian_ci",
Collation::ucs2_general_ci => "ucs2_general_ci",
Collation::ucs2_general_mysql500_ci => "ucs2_general_mysql500_ci",
Collation::ucs2_german2_ci => "ucs2_german2_ci",
Collation::ucs2_hungarian_ci => "ucs2_hungarian_ci",
Collation::ucs2_icelandic_ci => "ucs2_icelandic_ci",
Collation::ucs2_latvian_ci => "ucs2_latvian_ci",
Collation::ucs2_lithuanian_ci => "ucs2_lithuanian_ci",
Collation::ucs2_persian_ci => "ucs2_persian_ci",
Collation::ucs2_polish_ci => "ucs2_polish_ci",
Collation::ucs2_roman_ci => "ucs2_roman_ci",
Collation::ucs2_romanian_ci => "ucs2_romanian_ci",
Collation::ucs2_sinhala_ci => "ucs2_sinhala_ci",
Collation::ucs2_slovak_ci => "ucs2_slovak_ci",
Collation::ucs2_slovenian_ci => "ucs2_slovenian_ci",
Collation::ucs2_spanish_ci => "ucs2_spanish_ci",
Collation::ucs2_spanish2_ci => "ucs2_spanish2_ci",
Collation::ucs2_swedish_ci => "ucs2_swedish_ci",
Collation::ucs2_turkish_ci => "ucs2_turkish_ci",
Collation::ucs2_unicode_520_ci => "ucs2_unicode_520_ci",
Collation::ucs2_unicode_ci => "ucs2_unicode_ci",
Collation::ucs2_vietnamese_ci => "ucs2_vietnamese_ci",
Collation::ujis_bin => "ujis_bin",
Collation::ujis_japanese_ci => "ujis_japanese_ci",
Collation::utf16_bin => "utf16_bin",
Collation::utf16_croatian_ci => "utf16_croatian_ci",
Collation::utf16_czech_ci => "utf16_czech_ci",
Collation::utf16_danish_ci => "utf16_danish_ci",
Collation::utf16_esperanto_ci => "utf16_esperanto_ci",
Collation::utf16_estonian_ci => "utf16_estonian_ci",
Collation::utf16_general_ci => "utf16_general_ci",
Collation::utf16_german2_ci => "utf16_german2_ci",
Collation::utf16_hungarian_ci => "utf16_hungarian_ci",
Collation::utf16_icelandic_ci => "utf16_icelandic_ci",
Collation::utf16_latvian_ci => "utf16_latvian_ci",
Collation::utf16_lithuanian_ci => "utf16_lithuanian_ci",
Collation::utf16_persian_ci => "utf16_persian_ci",
Collation::utf16_polish_ci => "utf16_polish_ci",
Collation::utf16_roman_ci => "utf16_roman_ci",
Collation::utf16_romanian_ci => "utf16_romanian_ci",
Collation::utf16_sinhala_ci => "utf16_sinhala_ci",
Collation::utf16_slovak_ci => "utf16_slovak_ci",
Collation::utf16_slovenian_ci => "utf16_slovenian_ci",
Collation::utf16_spanish_ci => "utf16_spanish_ci",
Collation::utf16_spanish2_ci => "utf16_spanish2_ci",
Collation::utf16_swedish_ci => "utf16_swedish_ci",
Collation::utf16_turkish_ci => "utf16_turkish_ci",
Collation::utf16_unicode_520_ci => "utf16_unicode_520_ci",
Collation::utf16_unicode_ci => "utf16_unicode_ci",
Collation::utf16_vietnamese_ci => "utf16_vietnamese_ci",
Collation::utf16le_bin => "utf16le_bin",
Collation::utf16le_general_ci => "utf16le_general_ci",
Collation::utf32_bin => "utf32_bin",
Collation::utf32_croatian_ci => "utf32_croatian_ci",
Collation::utf32_czech_ci => "utf32_czech_ci",
Collation::utf32_danish_ci => "utf32_danish_ci",
Collation::utf32_esperanto_ci => "utf32_esperanto_ci",
Collation::utf32_estonian_ci => "utf32_estonian_ci",
Collation::utf32_general_ci => "utf32_general_ci",
Collation::utf32_german2_ci => "utf32_german2_ci",
Collation::utf32_hungarian_ci => "utf32_hungarian_ci",
Collation::utf32_icelandic_ci => "utf32_icelandic_ci",
Collation::utf32_latvian_ci => "utf32_latvian_ci",
Collation::utf32_lithuanian_ci => "utf32_lithuanian_ci",
Collation::utf32_persian_ci => "utf32_persian_ci",
Collation::utf32_polish_ci => "utf32_polish_ci",
Collation::utf32_roman_ci => "utf32_roman_ci",
Collation::utf32_romanian_ci => "utf32_romanian_ci",
Collation::utf32_sinhala_ci => "utf32_sinhala_ci",
Collation::utf32_slovak_ci => "utf32_slovak_ci",
Collation::utf32_slovenian_ci => "utf32_slovenian_ci",
Collation::utf32_spanish_ci => "utf32_spanish_ci",
Collation::utf32_spanish2_ci => "utf32_spanish2_ci",
Collation::utf32_swedish_ci => "utf32_swedish_ci",
Collation::utf32_turkish_ci => "utf32_turkish_ci",
Collation::utf32_unicode_520_ci => "utf32_unicode_520_ci",
Collation::utf32_unicode_ci => "utf32_unicode_ci",
Collation::utf32_vietnamese_ci => "utf32_vietnamese_ci",
Collation::utf8_bin => "utf8_bin",
Collation::utf8_croatian_ci => "utf8_croatian_ci",
Collation::utf8_czech_ci => "utf8_czech_ci",
Collation::utf8_danish_ci => "utf8_danish_ci",
Collation::utf8_esperanto_ci => "utf8_esperanto_ci",
Collation::utf8_estonian_ci => "utf8_estonian_ci",
Collation::utf8_general_ci => "utf8_general_ci",
Collation::utf8_general_mysql500_ci => "utf8_general_mysql500_ci",
Collation::utf8_german2_ci => "utf8_german2_ci",
Collation::utf8_hungarian_ci => "utf8_hungarian_ci",
Collation::utf8_icelandic_ci => "utf8_icelandic_ci",
Collation::utf8_latvian_ci => "utf8_latvian_ci",
Collation::utf8_lithuanian_ci => "utf8_lithuanian_ci",
Collation::utf8_persian_ci => "utf8_persian_ci",
Collation::utf8_polish_ci => "utf8_polish_ci",
Collation::utf8_roman_ci => "utf8_roman_ci",
Collation::utf8_romanian_ci => "utf8_romanian_ci",
Collation::utf8_sinhala_ci => "utf8_sinhala_ci",
Collation::utf8_slovak_ci => "utf8_slovak_ci",
Collation::utf8_slovenian_ci => "utf8_slovenian_ci",
Collation::utf8_spanish_ci => "utf8_spanish_ci",
Collation::utf8_spanish2_ci => "utf8_spanish2_ci",
Collation::utf8_swedish_ci => "utf8_swedish_ci",
Collation::utf8_tolower_ci => "utf8_tolower_ci",
Collation::utf8_turkish_ci => "utf8_turkish_ci",
Collation::utf8_unicode_520_ci => "utf8_unicode_520_ci",
Collation::utf8_unicode_ci => "utf8_unicode_ci",
Collation::utf8_vietnamese_ci => "utf8_vietnamese_ci",
Collation::utf8mb4_0900_ai_ci => "utf8mb4_0900_ai_ci",
Collation::utf8mb4_bin => "utf8mb4_bin",
Collation::utf8mb4_croatian_ci => "utf8mb4_croatian_ci",
Collation::utf8mb4_czech_ci => "utf8mb4_czech_ci",
Collation::utf8mb4_danish_ci => "utf8mb4_danish_ci",
Collation::utf8mb4_esperanto_ci => "utf8mb4_esperanto_ci",
Collation::utf8mb4_estonian_ci => "utf8mb4_estonian_ci",
Collation::utf8mb4_general_ci => "utf8mb4_general_ci",
Collation::utf8mb4_german2_ci => "utf8mb4_german2_ci",
Collation::utf8mb4_hungarian_ci => "utf8mb4_hungarian_ci",
Collation::utf8mb4_icelandic_ci => "utf8mb4_icelandic_ci",
Collation::utf8mb4_latvian_ci => "utf8mb4_latvian_ci",
Collation::utf8mb4_lithuanian_ci => "utf8mb4_lithuanian_ci",
Collation::utf8mb4_persian_ci => "utf8mb4_persian_ci",
Collation::utf8mb4_polish_ci => "utf8mb4_polish_ci",
Collation::utf8mb4_roman_ci => "utf8mb4_roman_ci",
Collation::utf8mb4_romanian_ci => "utf8mb4_romanian_ci",
Collation::utf8mb4_sinhala_ci => "utf8mb4_sinhala_ci",
Collation::utf8mb4_slovak_ci => "utf8mb4_slovak_ci",
Collation::utf8mb4_slovenian_ci => "utf8mb4_slovenian_ci",
Collation::utf8mb4_spanish_ci => "utf8mb4_spanish_ci",
Collation::utf8mb4_spanish2_ci => "utf8mb4_spanish2_ci",
Collation::utf8mb4_swedish_ci => "utf8mb4_swedish_ci",
Collation::utf8mb4_turkish_ci => "utf8mb4_turkish_ci",
Collation::utf8mb4_unicode_520_ci => "utf8mb4_unicode_520_ci",
Collation::utf8mb4_unicode_ci => "utf8mb4_unicode_ci",
Collation::utf8mb4_vietnamese_ci => "utf8mb4_vietnamese_ci",
}
}
}
// Handshake packet have only 1 byte for collation_id.
// So we can't use collations with ID > 255.
impl FromStr for Collation {
type Err = Error;
fn from_str(collation: &str) -> Result<Self, Self::Err> {
Ok(match collation {
"big5_chinese_ci" => Collation::big5_chinese_ci,
"swe7_swedish_ci" => Collation::swe7_swedish_ci,
"utf16_unicode_ci" => Collation::utf16_unicode_ci,
"utf16_icelandic_ci" => Collation::utf16_icelandic_ci,
"utf16_latvian_ci" => Collation::utf16_latvian_ci,
"utf16_romanian_ci" => Collation::utf16_romanian_ci,
"utf16_slovenian_ci" => Collation::utf16_slovenian_ci,
"utf16_polish_ci" => Collation::utf16_polish_ci,
"utf16_estonian_ci" => Collation::utf16_estonian_ci,
"utf16_spanish_ci" => Collation::utf16_spanish_ci,
"utf16_swedish_ci" => Collation::utf16_swedish_ci,
"ascii_general_ci" => Collation::ascii_general_ci,
"utf16_turkish_ci" => Collation::utf16_turkish_ci,
"utf16_czech_ci" => Collation::utf16_czech_ci,
"utf16_danish_ci" => Collation::utf16_danish_ci,
"utf16_lithuanian_ci" => Collation::utf16_lithuanian_ci,
"utf16_slovak_ci" => Collation::utf16_slovak_ci,
"utf16_spanish2_ci" => Collation::utf16_spanish2_ci,
"utf16_roman_ci" => Collation::utf16_roman_ci,
"utf16_persian_ci" => Collation::utf16_persian_ci,
"utf16_esperanto_ci" => Collation::utf16_esperanto_ci,
"utf16_hungarian_ci" => Collation::utf16_hungarian_ci,
"ujis_japanese_ci" => Collation::ujis_japanese_ci,
"utf16_sinhala_ci" => Collation::utf16_sinhala_ci,
"utf16_german2_ci" => Collation::utf16_german2_ci,
"utf16_croatian_ci" => Collation::utf16_croatian_ci,
"utf16_unicode_520_ci" => Collation::utf16_unicode_520_ci,
"utf16_vietnamese_ci" => Collation::utf16_vietnamese_ci,
"ucs2_unicode_ci" => Collation::ucs2_unicode_ci,
"ucs2_icelandic_ci" => Collation::ucs2_icelandic_ci,
"sjis_japanese_ci" => Collation::sjis_japanese_ci,
"ucs2_latvian_ci" => Collation::ucs2_latvian_ci,
"ucs2_romanian_ci" => Collation::ucs2_romanian_ci,
"ucs2_slovenian_ci" => Collation::ucs2_slovenian_ci,
"ucs2_polish_ci" => Collation::ucs2_polish_ci,
"ucs2_estonian_ci" => Collation::ucs2_estonian_ci,
"ucs2_spanish_ci" => Collation::ucs2_spanish_ci,
"ucs2_swedish_ci" => Collation::ucs2_swedish_ci,
"ucs2_turkish_ci" => Collation::ucs2_turkish_ci,
"ucs2_czech_ci" => Collation::ucs2_czech_ci,
"ucs2_danish_ci" => Collation::ucs2_danish_ci,
"cp1251_bulgarian_ci" => Collation::cp1251_bulgarian_ci,
"ucs2_lithuanian_ci" => Collation::ucs2_lithuanian_ci,
"ucs2_slovak_ci" => Collation::ucs2_slovak_ci,
"ucs2_spanish2_ci" => Collation::ucs2_spanish2_ci,
"ucs2_roman_ci" => Collation::ucs2_roman_ci,
"ucs2_persian_ci" => Collation::ucs2_persian_ci,
"ucs2_esperanto_ci" => Collation::ucs2_esperanto_ci,
"ucs2_hungarian_ci" => Collation::ucs2_hungarian_ci,
"ucs2_sinhala_ci" => Collation::ucs2_sinhala_ci,
"ucs2_german2_ci" => Collation::ucs2_german2_ci,
"ucs2_croatian_ci" => Collation::ucs2_croatian_ci,
"latin1_danish_ci" => Collation::latin1_danish_ci,
"ucs2_unicode_520_ci" => Collation::ucs2_unicode_520_ci,
"ucs2_vietnamese_ci" => Collation::ucs2_vietnamese_ci,
"ucs2_general_mysql500_ci" => Collation::ucs2_general_mysql500_ci,
"hebrew_general_ci" => Collation::hebrew_general_ci,
"utf32_unicode_ci" => Collation::utf32_unicode_ci,
"utf32_icelandic_ci" => Collation::utf32_icelandic_ci,
"utf32_latvian_ci" => Collation::utf32_latvian_ci,
"utf32_romanian_ci" => Collation::utf32_romanian_ci,
"utf32_slovenian_ci" => Collation::utf32_slovenian_ci,
"utf32_polish_ci" => Collation::utf32_polish_ci,
"utf32_estonian_ci" => Collation::utf32_estonian_ci,
"utf32_spanish_ci" => Collation::utf32_spanish_ci,
"utf32_swedish_ci" => Collation::utf32_swedish_ci,
"utf32_turkish_ci" => Collation::utf32_turkish_ci,
"utf32_czech_ci" => Collation::utf32_czech_ci,
"utf32_danish_ci" => Collation::utf32_danish_ci,
"utf32_lithuanian_ci" => Collation::utf32_lithuanian_ci,
"utf32_slovak_ci" => Collation::utf32_slovak_ci,
"utf32_spanish2_ci" => Collation::utf32_spanish2_ci,
"utf32_roman_ci" => Collation::utf32_roman_ci,
"utf32_persian_ci" => Collation::utf32_persian_ci,
"utf32_esperanto_ci" => Collation::utf32_esperanto_ci,
"utf32_hungarian_ci" => Collation::utf32_hungarian_ci,
"utf32_sinhala_ci" => Collation::utf32_sinhala_ci,
"tis620_thai_ci" => Collation::tis620_thai_ci,
"utf32_german2_ci" => Collation::utf32_german2_ci,
"utf32_croatian_ci" => Collation::utf32_croatian_ci,
"utf32_unicode_520_ci" => Collation::utf32_unicode_520_ci,
"utf32_vietnamese_ci" => Collation::utf32_vietnamese_ci,
"euckr_korean_ci" => Collation::euckr_korean_ci,
"utf8_unicode_ci" => Collation::utf8_unicode_ci,
"utf8_icelandic_ci" => Collation::utf8_icelandic_ci,
"utf8_latvian_ci" => Collation::utf8_latvian_ci,
"utf8_romanian_ci" => Collation::utf8_romanian_ci,
"utf8_slovenian_ci" => Collation::utf8_slovenian_ci,
"utf8_polish_ci" => Collation::utf8_polish_ci,
"utf8_estonian_ci" => Collation::utf8_estonian_ci,
"utf8_spanish_ci" => Collation::utf8_spanish_ci,
"latin2_czech_cs" => Collation::latin2_czech_cs,
"latin7_estonian_cs" => Collation::latin7_estonian_cs,
"utf8_swedish_ci" => Collation::utf8_swedish_ci,
"utf8_turkish_ci" => Collation::utf8_turkish_ci,
"utf8_czech_ci" => Collation::utf8_czech_ci,
"utf8_danish_ci" => Collation::utf8_danish_ci,
"utf8_lithuanian_ci" => Collation::utf8_lithuanian_ci,
"utf8_slovak_ci" => Collation::utf8_slovak_ci,
"utf8_spanish2_ci" => Collation::utf8_spanish2_ci,
"utf8_roman_ci" => Collation::utf8_roman_ci,
"utf8_persian_ci" => Collation::utf8_persian_ci,
"utf8_esperanto_ci" => Collation::utf8_esperanto_ci,
"latin2_hungarian_ci" => Collation::latin2_hungarian_ci,
"utf8_hungarian_ci" => Collation::utf8_hungarian_ci,
"utf8_sinhala_ci" => Collation::utf8_sinhala_ci,
"utf8_german2_ci" => Collation::utf8_german2_ci,
"utf8_croatian_ci" => Collation::utf8_croatian_ci,
"utf8_unicode_520_ci" => Collation::utf8_unicode_520_ci,
"utf8_vietnamese_ci" => Collation::utf8_vietnamese_ci,
"koi8u_general_ci" => Collation::koi8u_general_ci,
"utf8_general_mysql500_ci" => Collation::utf8_general_mysql500_ci,
"utf8mb4_unicode_ci" => Collation::utf8mb4_unicode_ci,
"utf8mb4_icelandic_ci" => Collation::utf8mb4_icelandic_ci,
"utf8mb4_latvian_ci" => Collation::utf8mb4_latvian_ci,
"utf8mb4_romanian_ci" => Collation::utf8mb4_romanian_ci,
"utf8mb4_slovenian_ci" => Collation::utf8mb4_slovenian_ci,
"utf8mb4_polish_ci" => Collation::utf8mb4_polish_ci,
"cp1251_ukrainian_ci" => Collation::cp1251_ukrainian_ci,
"utf8mb4_estonian_ci" => Collation::utf8mb4_estonian_ci,
"utf8mb4_spanish_ci" => Collation::utf8mb4_spanish_ci,
"utf8mb4_swedish_ci" => Collation::utf8mb4_swedish_ci,
"utf8mb4_turkish_ci" => Collation::utf8mb4_turkish_ci,
"utf8mb4_czech_ci" => Collation::utf8mb4_czech_ci,
"utf8mb4_danish_ci" => Collation::utf8mb4_danish_ci,
"utf8mb4_lithuanian_ci" => Collation::utf8mb4_lithuanian_ci,
"utf8mb4_slovak_ci" => Collation::utf8mb4_slovak_ci,
"utf8mb4_spanish2_ci" => Collation::utf8mb4_spanish2_ci,
"utf8mb4_roman_ci" => Collation::utf8mb4_roman_ci,
"gb2312_chinese_ci" => Collation::gb2312_chinese_ci,
"utf8mb4_persian_ci" => Collation::utf8mb4_persian_ci,
"utf8mb4_esperanto_ci" => Collation::utf8mb4_esperanto_ci,
"utf8mb4_hungarian_ci" => Collation::utf8mb4_hungarian_ci,
"utf8mb4_sinhala_ci" => Collation::utf8mb4_sinhala_ci,
"utf8mb4_german2_ci" => Collation::utf8mb4_german2_ci,
"utf8mb4_croatian_ci" => Collation::utf8mb4_croatian_ci,
"utf8mb4_unicode_520_ci" => Collation::utf8mb4_unicode_520_ci,
"utf8mb4_vietnamese_ci" => Collation::utf8mb4_vietnamese_ci,
"gb18030_chinese_ci" => Collation::gb18030_chinese_ci,
"gb18030_bin" => Collation::gb18030_bin,
"greek_general_ci" => Collation::greek_general_ci,
"gb18030_unicode_520_ci" => Collation::gb18030_unicode_520_ci,
"utf8mb4_0900_ai_ci" => Collation::utf8mb4_0900_ai_ci,
"cp1250_general_ci" => Collation::cp1250_general_ci,
"latin2_croatian_ci" => Collation::latin2_croatian_ci,
"gbk_chinese_ci" => Collation::gbk_chinese_ci,
"cp1257_lithuanian_ci" => Collation::cp1257_lithuanian_ci,
"dec8_swedish_ci" => Collation::dec8_swedish_ci,
"latin5_turkish_ci" => Collation::latin5_turkish_ci,
"latin1_german2_ci" => Collation::latin1_german2_ci,
"armscii8_general_ci" => Collation::armscii8_general_ci,
"utf8_general_ci" => Collation::utf8_general_ci,
"cp1250_czech_cs" => Collation::cp1250_czech_cs,
"ucs2_general_ci" => Collation::ucs2_general_ci,
"cp866_general_ci" => Collation::cp866_general_ci,
"keybcs2_general_ci" => Collation::keybcs2_general_ci,
"macce_general_ci" => Collation::macce_general_ci,
"macroman_general_ci" => Collation::macroman_general_ci,
"cp850_general_ci" => Collation::cp850_general_ci,
"cp852_general_ci" => Collation::cp852_general_ci,
"latin7_general_ci" => Collation::latin7_general_ci,
"latin7_general_cs" => Collation::latin7_general_cs,
"macce_bin" => Collation::macce_bin,
"cp1250_croatian_ci" => Collation::cp1250_croatian_ci,
"utf8mb4_general_ci" => Collation::utf8mb4_general_ci,
"utf8mb4_bin" => Collation::utf8mb4_bin,
"latin1_bin" => Collation::latin1_bin,
"latin1_general_ci" => Collation::latin1_general_ci,
"latin1_general_cs" => Collation::latin1_general_cs,
"latin1_german1_ci" => Collation::latin1_german1_ci,
"cp1251_bin" => Collation::cp1251_bin,
"cp1251_general_ci" => Collation::cp1251_general_ci,
"cp1251_general_cs" => Collation::cp1251_general_cs,
"macroman_bin" => Collation::macroman_bin,
"utf16_general_ci" => Collation::utf16_general_ci,
"utf16_bin" => Collation::utf16_bin,
"utf16le_general_ci" => Collation::utf16le_general_ci,
"cp1256_general_ci" => Collation::cp1256_general_ci,
"cp1257_bin" => Collation::cp1257_bin,
"cp1257_general_ci" => Collation::cp1257_general_ci,
"hp8_english_ci" => Collation::hp8_english_ci,
"utf32_general_ci" => Collation::utf32_general_ci,
"utf32_bin" => Collation::utf32_bin,
"utf16le_bin" => Collation::utf16le_bin,
"binary" => Collation::binary,
"armscii8_bin" => Collation::armscii8_bin,
"ascii_bin" => Collation::ascii_bin,
"cp1250_bin" => Collation::cp1250_bin,
"cp1256_bin" => Collation::cp1256_bin,
"cp866_bin" => Collation::cp866_bin,
"dec8_bin" => Collation::dec8_bin,
"koi8r_general_ci" => Collation::koi8r_general_ci,
"greek_bin" => Collation::greek_bin,
"hebrew_bin" => Collation::hebrew_bin,
"hp8_bin" => Collation::hp8_bin,
"keybcs2_bin" => Collation::keybcs2_bin,
"koi8r_bin" => Collation::koi8r_bin,
"koi8u_bin" => Collation::koi8u_bin,
"utf8_tolower_ci" => Collation::utf8_tolower_ci,
"latin2_bin" => Collation::latin2_bin,
"latin5_bin" => Collation::latin5_bin,
"latin7_bin" => Collation::latin7_bin,
"latin1_swedish_ci" => Collation::latin1_swedish_ci,
"cp850_bin" => Collation::cp850_bin,
"cp852_bin" => Collation::cp852_bin,
"swe7_bin" => Collation::swe7_bin,
"utf8_bin" => Collation::utf8_bin,
"big5_bin" => Collation::big5_bin,
"euckr_bin" => Collation::euckr_bin,
"gb2312_bin" => Collation::gb2312_bin,
"gbk_bin" => Collation::gbk_bin,
"sjis_bin" => Collation::sjis_bin,
"tis620_bin" => Collation::tis620_bin,
"latin2_general_ci" => Collation::latin2_general_ci,
"ucs2_bin" => Collation::ucs2_bin,
"ujis_bin" => Collation::ujis_bin,
"geostd8_general_ci" => Collation::geostd8_general_ci,
"geostd8_bin" => Collation::geostd8_bin,
"latin1_spanish_ci" => Collation::latin1_spanish_ci,
"cp932_japanese_ci" => Collation::cp932_japanese_ci,
"cp932_bin" => Collation::cp932_bin,
"eucjpms_japanese_ci" => Collation::eucjpms_japanese_ci,
"eucjpms_bin" => Collation::eucjpms_bin,
"cp1250_polish_ci" => Collation::cp1250_polish_ci,
_ => {
return Err(Error::Configuration(
format!("unsupported MySQL collation: {collation}").into(),
));
}
})
}
/// Collation used for all non-string data.
pub const BINARY: Self = Collation(63);
/// Most broadly supported UTF-8 collation.
pub const UTF8MB4_GENERAL_CI: Self = Collation(45);
}

View File

@ -1,7 +1,6 @@
use bytes::buf::Buf;
use bytes::Bytes;
use crate::collation::{CharSet, Collation};
use crate::common::StatementCache;
use crate::connection::{tls, MySqlConnectionInner, MySqlStream, MAX_PACKET_SIZE};
use crate::error::Error;
@ -37,20 +36,10 @@ impl MySqlConnection {
struct DoHandshake<'a> {
options: &'a MySqlConnectOptions,
charset: CharSet,
collation: Collation,
}
impl<'a> DoHandshake<'a> {
fn new(options: &'a MySqlConnectOptions) -> Result<Self, Error> {
let charset: CharSet = options.charset.parse()?;
let collation: Collation = options
.collation
.as_deref()
.map(|collation| collation.parse())
.transpose()?
.unwrap_or_else(|| charset.default_collation());
if options.enable_cleartext_plugin
&& matches!(
options.ssl_mode,
@ -60,21 +49,13 @@ impl<'a> DoHandshake<'a> {
log::warn!("Security warning: sending cleartext passwords without requiring SSL");
}
Ok(Self {
options,
charset,
collation,
})
Ok(Self { options })
}
async fn do_handshake<S: Socket>(self, socket: S) -> Result<MySqlStream, Error> {
let DoHandshake {
options,
charset,
collation,
} = self;
let DoHandshake { options } = self;
let mut stream = MySqlStream::with_socket(charset, collation, options, socket);
let mut stream = MySqlStream::with_socket(options, socket);
// https://dev.mysql.com/doc/internals/en/connection-phase.html
// https://mariadb.com/kb/en/connection/
@ -125,7 +106,7 @@ impl<'a> DoHandshake<'a> {
};
stream.write_packet(HandshakeResponse {
collation: stream.collation as u8,
charset: super::INITIAL_CHARSET,
max_packet_size: MAX_PACKET_SIZE,
username: &options.username,
database: options.database.as_deref(),

View File

@ -5,6 +5,7 @@ pub(crate) use sqlx_core::connection::*;
use sqlx_core::sql_str::SqlSafeStr;
pub(crate) use stream::{MySqlStream, Waiting};
use crate::collation::Collation;
use crate::common::StatementCache;
use crate::error::Error;
use crate::protocol::response::Status;
@ -22,6 +23,13 @@ mod tls;
const MAX_PACKET_SIZE: u32 = 1024;
/// The charset parameter sent in the `Protocol::HandshakeResponse41` packet.
///
/// This becomes the default if `set_names = false`,
/// and also ensures that any error messages returned before `SET NAMES` are encoded correctly.
#[allow(clippy::cast_possible_truncation)]
const INITIAL_CHARSET: u8 = Collation::UTF8MB4_GENERAL_CI.0 as u8;
/// A connection to a MySQL database.
pub struct MySqlConnection {
pub(crate) inner: Box<MySqlConnectionInner>,

View File

@ -3,7 +3,6 @@ use std::ops::{Deref, DerefMut};
use bytes::{Buf, Bytes, BytesMut};
use crate::collation::{CharSet, Collation};
use crate::error::Error;
use crate::io::MySqlBufExt;
use crate::io::{ProtocolDecode, ProtocolEncode};
@ -19,8 +18,6 @@ pub struct MySqlStream<S = Box<dyn Socket>> {
pub(super) capabilities: Capabilities,
pub(crate) sequence_id: u8,
pub(crate) waiting: VecDeque<Waiting>,
pub(crate) charset: CharSet,
pub(crate) collation: Collation,
pub(crate) is_tls: bool,
}
@ -34,12 +31,7 @@ pub(crate) enum Waiting {
}
impl<S: Socket> MySqlStream<S> {
pub(crate) fn with_socket(
charset: CharSet,
collation: Collation,
options: &MySqlConnectOptions,
socket: S,
) -> Self {
pub(crate) fn with_socket(options: &MySqlConnectOptions, socket: S) -> Self {
let mut capabilities = Capabilities::PROTOCOL_41
| Capabilities::IGNORE_SPACE
| Capabilities::DEPRECATE_EOF
@ -62,8 +54,6 @@ impl<S: Socket> MySqlStream<S> {
capabilities,
server_version: (0, 0, 0),
sequence_id: 0,
collation,
charset,
socket: BufferedSocket::new(socket),
is_tls: false,
}
@ -222,8 +212,6 @@ impl<S: Socket> MySqlStream<S> {
capabilities: self.capabilities,
sequence_id: self.sequence_id,
waiting: self.waiting,
charset: self.charset,
collation: self.collation,
is_tls: self.is_tls,
}
}

View File

@ -1,4 +1,3 @@
use crate::collation::{CharSet, Collation};
use crate::connection::{MySqlStream, Waiting};
use crate::error::Error;
use crate::net::tls::TlsConfig;
@ -13,8 +12,6 @@ struct MapStream {
capabilities: Capabilities,
sequence_id: u8,
waiting: VecDeque<Waiting>,
charset: CharSet,
collation: Collation,
}
pub(super) async fn maybe_upgrade<S: Socket>(
@ -71,7 +68,7 @@ pub(super) async fn maybe_upgrade<S: Socket>(
// Request TLS upgrade
stream.write_packet(SslRequest {
max_packet_size: super::MAX_PACKET_SIZE,
collation: stream.collation as u8,
charset: super::INITIAL_CHARSET,
})?;
stream.flush().await?;
@ -84,8 +81,6 @@ pub(super) async fn maybe_upgrade<S: Socket>(
capabilities: stream.capabilities,
sequence_id: stream.sequence_id,
waiting: stream.waiting,
charset: stream.charset,
collation: stream.collation,
},
)
.await
@ -101,8 +96,6 @@ impl WithSocket for MapStream {
capabilities: self.capabilities,
sequence_id: self.sequence_id,
waiting: self.waiting,
charset: self.charset,
collation: self.collation,
is_tls: true,
}
}

View File

@ -64,15 +64,23 @@ impl ConnectOptions for MySqlConnectOptions {
sql_mode.join(",")
));
}
if let Some(timezone) = &self.timezone {
options.push(format!(r#"time_zone='{}'"#, timezone));
}
if self.set_names {
options.push(format!(
r#"NAMES {} COLLATE {}"#,
conn.inner.stream.charset.as_str(),
conn.inner.stream.collation.as_str()
))
// As it turns out, we don't _have_ to set a collation if we don't want to.
// We can let the server choose the default collation for the charset.
let set_names = if let Some(collation) = &self.collation {
format!(r#"NAMES {} COLLATE {collation}"#, self.charset,)
} else {
// Leaves the default collation up to the server,
// but ensures statements and results are encoded using the proper charset.
format!("NAMES {}", self.charset)
};
options.push(set_names);
}
if !options.is_empty() {

View File

@ -301,16 +301,24 @@ impl MySqlConnectOptions {
///
/// The default character set is `utf8mb4`. This is supported from MySQL 5.5.3.
/// If you need to connect to an older version, we recommend you to change this to `utf8`.
///
/// Implies [`.set_names(true)`][Self::set_names()].
pub fn charset(mut self, charset: &str) -> Self {
self.set_names = true;
charset.clone_into(&mut self.charset);
self
}
/// Sets the collation for the connection.
///
/// The default collation is derived from the `charset`. Normally, you should only have to set
/// the `charset`.
/// The default collation is derived on the server from the `charset`, if set.
/// Normally, you should only have to set the `charset`.
///
/// If setting this, it is recommended to also set [`charset`][Self::charset()].
///
/// Implies [`.set_names(true)`][Self::set_names()].
pub fn collation(mut self, collation: &str) -> Self {
self.set_names = true;
self.collation = Some(collation.to_owned());
self
}
@ -381,8 +389,9 @@ impl MySqlConnectOptions {
self
}
/// If enabled, `SET NAMES '{charset}' COLLATE '{collation}'` is passed with the values of
/// [`.charset()`] and [`.collation()`] after connecting to the database.
/// If enabled, [`.charset()`] and [`.collation()`] are set with the appropriate command.
///
/// If only `.charset()`
///
/// This ensures the connection uses the specified character set and collation.
///
@ -399,6 +408,8 @@ impl MySqlConnectOptions {
///
/// Instead of disabling this, you may also consider setting [`.charset()`] to a charset that
/// is supported by your MySQL or MariaDB server version and compatible with UTF-8.
///
/// [`.charset`]: Self::charset()
pub fn set_names(mut self, flag_val: bool) -> Self {
self.set_names = flag_val;
self

View File

@ -14,8 +14,8 @@ pub struct HandshakeResponse<'a> {
/// Max size of a command packet that the client wants to send to the server
pub max_packet_size: u32,
/// Default collation for the connection
pub collation: u8,
/// Default charset (collation ID < 256) for the connection
pub charset: u8,
/// Name of the SQL account which client wants to log in
pub username: &'a str,
@ -41,7 +41,7 @@ impl ProtocolEncode<'_, Capabilities> for HandshakeResponse<'_> {
// NOTE: Half of this packet is identical to the SSL Request packet
SslRequest {
max_packet_size: self.max_packet_size,
collation: self.collation,
charset: self.charset,
}
.encode_with(buf, context)?;

View File

@ -7,7 +7,7 @@ use crate::protocol::Capabilities;
#[derive(Debug)]
pub struct SslRequest {
pub max_packet_size: u32,
pub collation: u8,
pub charset: u8,
}
impl ProtocolEncode<'_, Capabilities> for SslRequest {
@ -16,7 +16,7 @@ impl ProtocolEncode<'_, Capabilities> for SslRequest {
#[allow(clippy::cast_possible_truncation)]
buf.extend(&(context.bits() as u32).to_le_bytes());
buf.extend(&self.max_packet_size.to_le_bytes());
buf.push(self.collation);
buf.push(self.charset);
// reserved: string<19>
buf.extend(&[0_u8; 19]);

View File

@ -1,12 +1,12 @@
use std::str;
use bitflags::bitflags;
use bytes::{Buf, Bytes};
use crate::collation::Collation;
use crate::error::Error;
use crate::io::MySqlBufExt;
use crate::io::ProtocolDecode;
use crate::protocol::Capabilities;
use bitflags::bitflags;
use bytes::{Buf, Bytes};
// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/group__group__cs__column__definition__flags.html
@ -110,8 +110,7 @@ pub(crate) struct ColumnDefinition {
table: Bytes,
alias: Bytes,
name: Bytes,
#[allow(unused)]
pub(crate) collation: u16,
pub(crate) collation: Collation,
pub(crate) max_size: u32,
pub(crate) r#type: ColumnType,
pub(crate) flags: ColumnFlags,
@ -162,7 +161,7 @@ impl ProtocolDecode<'_, Capabilities> for ColumnDefinition {
table,
alias,
name,
collation,
collation: Collation(collation),
max_size,
r#type: ColumnType::try_from_u16(type_id)?,
flags: ColumnFlags::from_bits_truncate(flags),

View File

@ -1,8 +1,8 @@
use std::fmt::{self, Display, Formatter};
pub(crate) use sqlx_core::type_info::*;
use crate::collation::Collation;
use crate::protocol::text::{ColumnDefinition, ColumnFlags, ColumnType};
pub(crate) use sqlx_core::type_info::*;
/// Type information for a MySql type.
#[derive(Debug, Clone)]
@ -10,6 +10,7 @@ use crate::protocol::text::{ColumnDefinition, ColumnFlags, ColumnType};
pub struct MySqlTypeInfo {
pub(crate) r#type: ColumnType,
pub(crate) flags: ColumnFlags,
pub(crate) collation: Collation,
// [max_size] for integer types, this is (M) in BIT(M) or TINYINT(M)
#[cfg_attr(feature = "offline", serde(default))]
@ -21,6 +22,7 @@ impl MySqlTypeInfo {
Self {
r#type: ty,
flags: ColumnFlags::BINARY,
collation: Collation::BINARY,
max_size: None,
}
}
@ -38,6 +40,7 @@ impl MySqlTypeInfo {
Self {
r#type: ColumnType::String,
flags: ColumnFlags::ENUM,
collation: Collation::UTF8MB4_GENERAL_CI,
max_size: None,
}
}
@ -60,6 +63,7 @@ impl MySqlTypeInfo {
Self {
r#type: column.r#type,
flags: column.flags,
collation: column.collation,
max_size: Some(column.max_size),
}
}

View File

@ -1,3 +1,4 @@
use crate::collation::Collation;
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
@ -9,9 +10,10 @@ use crate::{
impl Type<MySql> for bool {
fn type_info() -> MySqlTypeInfo {
// MySQL has no actual `BOOLEAN` type, the type is an alias of `TINYINT(1)`
// MySQL has no actual `BOOLEAN` type, the type is an alias of `[UNSIGNED] TINYINT(1)`
MySqlTypeInfo {
flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,
collation: Collation::BINARY,
max_size: Some(1),
r#type: ColumnType::Tiny,
}

View File

@ -2,6 +2,7 @@ use std::borrow::Cow;
use std::rc::Rc;
use std::sync::Arc;
use crate::collation::Collation;
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
@ -15,6 +16,8 @@ impl Type<MySql> for str {
MySqlTypeInfo {
r#type: ColumnType::VarString, // VARCHAR
flags: ColumnFlags::empty(),
// Doesn't matter because we never send this.
collation: Collation::UTF8MB4_GENERAL_CI,
max_size: None,
}
}
@ -31,7 +34,13 @@ impl Type<MySql> for str {
| ColumnType::String
| ColumnType::VarString
| ColumnType::Enum
) && !ty.flags.contains(ColumnFlags::BINARY)
)
// Any collation that *isn't* `binary` generally indicates string data.
// The actual collation used for storage doesn't matter,
// because the server will transcode to the charset we specify.
//
// See comment in `src/collation.rs` for details.
&& ty.collation != Collation::BINARY
}
}

View File

@ -1,3 +1,4 @@
use crate::collation::Collation;
use crate::decode::Decode;
use crate::encode::{Encode, IsNull};
use crate::error::BoxDynError;
@ -10,6 +11,7 @@ fn uint_type_info(ty: ColumnType) -> MySqlTypeInfo {
MySqlTypeInfo {
r#type: ty,
flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,
collation: Collation::BINARY,
max_size: None,
}
}

View File

@ -58,15 +58,43 @@ services:
MYSQL_DATABASE: sqlx
MYSQL_ALLOW_EMPTY_PASSWORD: 1
#
# MariaDB 10.11, 10.6, 10.5, 10.4
# MariaDB
# Testing will be dropped when Community Support ends.
# https://mariadb.org/about/#maintenance-policy
#
# EOL: 2028/06/04 (sooner than 11.4 for some reason)
mariadb_11_8:
image: mariadb:11.8
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
MARIADB_ROOT_PASSWORD: password
MARIADB_DATABASE: sqlx
mariadb_11_8_client_ssl:
build:
context: .
dockerfile: mysql/Dockerfile
args:
IMAGE: mariadb:11.8
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
MARIADB_DATABASE: sqlx
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1
# EOL: 2029/05/29
mariadb_11_4:
image: mariadb:11.4
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
@ -81,16 +109,19 @@ services:
IMAGE: mariadb:11.4
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
MARIADB_DATABASE: sqlx
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1
# EOL: 2028/02/16
mariadb_10_11:
image: mariadb:10.11
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
@ -105,16 +136,20 @@ services:
IMAGE: mariadb:10.11
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
MARIADB_DATABASE: sqlx
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1
# EOL: 2026/07/06
mariadb_10_6:
image: mariadb:10.6
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
# UUID support was not added until 10.10
# - "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
@ -129,54 +164,8 @@ services:
IMAGE: mariadb:10.6
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
ports:
- 3306
environment:
MARIADB_DATABASE: sqlx
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1
mariadb_10_5:
image: mariadb:10.5
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
ports:
- 3306
environment:
MARIADB_ROOT_PASSWORD: password
MARIADB_DATABASE: sqlx
mariadb_10_5_client_ssl:
build:
context: .
dockerfile: mysql/Dockerfile
args:
IMAGE: mariadb:10.5
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
ports:
- 3306
environment:
MARIADB_DATABASE: sqlx
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1
mariadb_10_4:
image: mariadb:10.4
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
ports:
- 3306
environment:
MARIADB_ROOT_PASSWORD: password
MARIADB_DATABASE: sqlx
mariadb_10_4_client_ssl:
build:
context: .
dockerfile: mysql/Dockerfile
args:
IMAGE: mariadb:10.4
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
# UUID support was not added until 10.10
# - "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
@ -189,6 +178,7 @@ services:
image: quay.io/mariadb-foundation/mariadb-devel:verylatest
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:
@ -203,6 +193,7 @@ services:
IMAGE: quay.io/mariadb-foundation/mariadb-devel:verylatest
volumes:
- "./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z"
- "./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z"
ports:
- 3306
environment:

View File

@ -555,4 +555,34 @@ async fn test_from_row_json_try_from_attr() -> anyhow::Result<()> {
Ok(())
}
#[cfg(all(mariadb, not(mariadb = "10_6"), feature = "time"))]
#[sqlx_macros::test]
async fn test_uuid_is_compatible_mariadb() -> anyhow::Result<()> {
use sqlx::types::time::OffsetDateTime;
use sqlx::types::Uuid;
struct Tweet {
id: Uuid,
text: String,
created_at: OffsetDateTime,
owner_id: Option<Uuid>,
}
let mut conn = new::<MySql>().await?;
sqlx::query!("INSERT INTO tweet_with_uuid(text) VALUES ('Hello, world!')")
.execute(&mut conn)
.await?;
let tweets: Vec<Tweet> = sqlx::query_as!(Tweet, "SELECT * FROM tweet_with_uuid")
.fetch_all(&mut conn)
.await?;
assert_eq!(tweets.len(), 1);
assert_eq!(tweets[0].text, "Hello, world!");
Ok(())
}
// we don't emit bind parameter type-checks for MySQL so testing the overrides is redundant

View File

@ -605,3 +605,34 @@ async fn select_statement_count(conn: &mut MySqlConnection) -> Result<i64, sqlx:
.fetch_one(conn)
.await
}
#[sqlx_macros::test]
async fn issue_3200() -> anyhow::Result<()> {
let mut conn = new::<MySql>().await?;
sqlx::raw_sql(
"\
CREATE TABLE IF NOT EXISTS users
(
`id` BIGINT AUTO_INCREMENT,
`username` VARCHAR(128) NOT NULL,
PRIMARY KEY (id)
);
",
)
.execute(&mut conn)
.await?;
let result = sqlx::raw_sql(
"\
SET @myvar := 'test@test.com';
select id from users where username = @myvar;
",
)
.fetch_optional(&mut conn)
.await?;
assert!(result.is_none(), "{result:?}");
Ok(())
}

View File

@ -0,0 +1,10 @@
-- additional SQL to execute for MariaDB databases
CREATE TABLE tweet_with_uuid
(
-- UUID is only a bespoke datatype in MariaDB.
id UUID PRIMARY KEY DEFAULT UUID(),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
text TEXT NOT NULL,
owner_id UUID
);