@@ -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 }
0 commit comments