Skip to content

Commit 8257d06

Browse files
authored
Add support for MEDIUMBLOB and CHAR (#2)
* Make the data in a Blob readable * Add some support for reading the Table_map_event with MYSQL_TYPE_STRING Add support for parsing CHAR(n) columns BINARY(n) columns no longer cause a panic, but the value is not usable (since it is converted to utf-8). SET and ENUM columns no longer panic in read_metadata, but they still panic in read_value
1 parent c2b885c commit 8257d06

File tree

2 files changed

+35
-12
lines changed

2 files changed

+35
-12
lines changed

src/column_types.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub enum ColumnType {
3131
Bit(u8, u8),
3232
NewDecimal(u8, u8),
3333
Enum(u16),
34-
Set,
34+
Set(u16),
3535
TinyBlob,
3636
MediumBlob,
3737
LongBlob,
@@ -68,7 +68,8 @@ impl ColumnType {
6868
245 => ColumnType::Json(0), // need to implement JsonB
6969
246 => ColumnType::NewDecimal(0, 0),
7070
247 => ColumnType::Enum(0),
71-
248 => ColumnType::TinyBlob, // docs say this can't occur
71+
248 => ColumnType::Set(0),
72+
249 => ColumnType::TinyBlob, // docs say this can't occur
7273
250 => ColumnType::MediumBlob, // docs say this can't occur
7374
251 => ColumnType::LongBlob, // docs say this can't occur
7475
252 => ColumnType::Blob(0),
@@ -97,7 +98,7 @@ impl ColumnType {
9798
let pack_length = cursor.read_u8()?;
9899
ColumnType::Geometry(pack_length)
99100
}
100-
ColumnType::VarChar(_) => {
101+
ColumnType::VarString | ColumnType::VarChar(_) => {
101102
let max_length = cursor.read_u16::<LittleEndian>()?;
102103
assert!(max_length != 0);
103104
ColumnType::VarChar(max_length)
@@ -108,15 +109,33 @@ impl ColumnType {
108109
let num_decimals = cursor.read_u8()?;
109110
ColumnType::NewDecimal(precision, num_decimals)
110111
}
111-
ColumnType::VarString | ColumnType::MyString => {
112+
ColumnType::MyString => {
113+
// In Table_map_event, column type MYSQL_TYPE_STRING
114+
// can have the following real_type:
115+
// * MYSQL_TYPE_STRING (used for CHAR(n) and BINARY(n) SQL types with n <=255)
116+
// * MYSQL_TYPE_ENUM
117+
// * MYSQL_TYPE_SET
112118
let f1 = cursor.read_u8()?;
113119
let f2 = cursor.read_u8()?;
114-
let real_type = f1;
115-
let real_type = ColumnType::from_byte(real_type);
116-
let real_size: u16 = f2.into();
117-
// XXX todo this actually includes some of the bits from f1
120+
let (real_type, max_length) = if f1 == 0 {
121+
// not sure which version of mysql emits this,
122+
// but log_event.cc checks this case
123+
(ColumnType::MyString, f2 as u16)
124+
} else {
125+
// The max length is in 0-1023,
126+
// (since CHAR(255) CHARACTER SET utf8mb4 turns into max_length=1020)
127+
// and the upper 4 bits of real_type are always set
128+
// (in real_type = MYSQL_TYPE_ENUM, MYSQL_TYPE_SET, MYSQL_TYPE_STRING)
129+
// So MySQL packs the upper bits of the length
130+
// in the 0x30 bits of the type, inverted
131+
let real_type = f1 | 0x30;
132+
let max_length = (!f1 as u16) << 4 & 0x300 | f2 as u16;
133+
(ColumnType::from_byte(real_type), max_length)
134+
};
118135
match real_type {
119-
ColumnType::Enum(_) => ColumnType::Enum(real_size),
136+
ColumnType::MyString => ColumnType::VarChar(max_length),
137+
ColumnType::Set(_) => ColumnType::Set(max_length),
138+
ColumnType::Enum(_) => ColumnType::Enum(max_length),
120139
i => unimplemented!("unimplemented stringy type {:?}", i),
121140
}
122141
}
@@ -152,6 +171,10 @@ impl ColumnType {
152171
}
153172
&ColumnType::Null => Ok(MySQLValue::Null),
154173
&ColumnType::VarChar(max_len) => {
174+
// TODO: don't decode to String,
175+
// since type=real_type=MYSQL_TYPE_STRING is used for BINARY(n)
176+
// and type=MYSQL_TYPE_VARCHAR is used for VARBINARY(n)
177+
// and also the CHAR(n) and VARCHAR(n) encoding is not always utf-8
155178
let value = if max_len > 255 {
156179
read_two_byte_length_prefixed_string(r)?
157180
} else {
@@ -317,7 +340,7 @@ impl ColumnType {
317340
&ColumnType::Decimal
318341
| &ColumnType::NewDate
319342
| &ColumnType::Bit(..)
320-
| &ColumnType::Set
343+
| &ColumnType::Set(..)
321344
| &ColumnType::Geometry(..) => {
322345
unimplemented!("unhandled value type: {:?}", self);
323346
}

src/value.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use std::borrow::Cow;
33
use serde::{Serialize, Serializer};
44

55
#[derive(Debug)]
6-
/// Wrapper for the SQL BLOB (Binary Large OBject) type
6+
/// Wrapper for the SQL BLOB (Binary Large OBject) and TEXT types
77
///
88
/// Serializes as Base64
9-
pub struct Blob(Vec<u8>);
9+
pub struct Blob(pub Vec<u8>);
1010

1111
impl From<Vec<u8>> for Blob {
1212
fn from(v: Vec<u8>) -> Self {

0 commit comments

Comments
 (0)