mysql_common/value/
mod.rs

1// Copyright (c) 2017 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use bytes::BufMut;
10
11use std::{convert::TryFrom, fmt, io, marker::PhantomData, str::from_utf8};
12
13use crate::{
14    constants::{ColumnFlags, ColumnType},
15    io::{BufMutExt, ParseBuf},
16    misc::{
17        lenenc_str_len,
18        raw::bytes::{LenEnc, RawBytes},
19        unexpected_buf_eof,
20    },
21    proto::{MyDeserialize, MySerialize},
22    value::Value::*,
23};
24
25pub mod convert;
26pub mod json;
27
28/// Side of MySql value serialization.
29pub trait SerializationSide {
30    /// Null-bitmap offset of this side.
31    const BIT_OFFSET: usize;
32}
33
34/// Server side serialization. Null-bitmap bit offset: `2`.
35#[derive(Debug, Clone, Copy, Eq, PartialEq)]
36pub struct ServerSide;
37
38impl SerializationSide for ServerSide {
39    const BIT_OFFSET: usize = 2;
40}
41
42/// Client side serialization. Null-bitmap bit offset: `0`.
43pub struct ClientSide;
44
45impl SerializationSide for ClientSide {
46    const BIT_OFFSET: usize = 0;
47}
48
49/// Textual value representation.
50pub struct TextValue;
51
52/// Binary value representation.
53pub struct BinValue;
54
55/// Client side representation of a value of MySql column.
56///
57/// The `Value` is also used as a parameter to a prepared statement.
58#[derive(Clone, PartialEq, PartialOrd)]
59pub enum Value {
60    NULL,
61    Bytes(Vec<u8>),
62    Int(i64),
63    UInt(u64),
64    Float(f32),
65    Double(f64),
66    /// year, month, day, hour, minutes, seconds, micro seconds
67    Date(u16, u8, u8, u8, u8, u8, u32),
68    /// is negative, days, hours, minutes, seconds, micro seconds
69    Time(bool, u32, u8, u8, u8, u32),
70}
71
72impl MySerialize for Value {
73    fn serialize(&self, buf: &mut Vec<u8>) {
74        match self {
75            Self::NULL => (),
76            Value::Bytes(x) => {
77                buf.put_lenenc_str(x);
78            }
79            Value::Int(x) => {
80                buf.put_i64_le(*x);
81            }
82            Value::UInt(x) => {
83                buf.put_u64_le(*x);
84            }
85            Value::Float(x) => {
86                buf.put_f32_le(*x);
87            }
88            Value::Double(x) => {
89                buf.put_f64_le(*x);
90            }
91            Value::Date(0u16, 0u8, 0u8, 0u8, 0u8, 0u8, 0u32) => {
92                buf.put_u8(0);
93            }
94            Value::Date(year, mon, day, 0u8, 0u8, 0u8, 0u32) => {
95                buf.put_u8(4);
96                buf.put_u16_le(*year);
97                buf.put_u8(*mon);
98                buf.put_u8(*day);
99            }
100            Value::Date(year, mon, day, hour, min, sec, 0u32) => {
101                buf.put_u8(7);
102                buf.put_u16_le(*year);
103                buf.put_u8(*mon);
104                buf.put_u8(*day);
105                buf.put_u8(*hour);
106                buf.put_u8(*min);
107                buf.put_u8(*sec);
108            }
109            Value::Date(year, mon, day, hour, min, sec, usec) => {
110                buf.put_u8(11);
111                buf.put_u16_le(*year);
112                buf.put_u8(*mon);
113                buf.put_u8(*day);
114                buf.put_u8(*hour);
115                buf.put_u8(*min);
116                buf.put_u8(*sec);
117                buf.put_u32_le(*usec);
118            }
119            Value::Time(_, 0u32, 0u8, 0u8, 0u8, 0u32) => {
120                buf.put_u8(0);
121            }
122            Value::Time(neg, d, h, m, s, 0u32) => {
123                buf.put_u8(8);
124                buf.put_u8(if *neg { 1 } else { 0 });
125                buf.put_u32_le(*d);
126                buf.put_u8(*h);
127                buf.put_u8(*m);
128                buf.put_u8(*s);
129            }
130            Value::Time(neg, days, hours, mins, secs, usecs) => {
131                buf.put_u8(12);
132                buf.put_u8(if *neg { 1 } else { 0 });
133                buf.put_u32_le(*days);
134                buf.put_u8(*hours);
135                buf.put_u8(*mins);
136                buf.put_u8(*secs);
137                buf.put_u32_le(*usecs);
138            }
139        }
140    }
141}
142
143/// Deserializer for a MySql value.
144///
145/// `T` specifies the value representation (textual or binary).
146#[derive(Debug, Clone, PartialEq)]
147pub struct ValueDeserializer<T>(pub Value, PhantomData<T>);
148
149impl<'de> MyDeserialize<'de> for ValueDeserializer<TextValue> {
150    const SIZE: Option<usize> = None;
151    type Ctx = ();
152
153    fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
154        let value = Value::deserialize_text(buf)?;
155        Ok(Self(value, PhantomData))
156    }
157}
158
159impl<'de> MyDeserialize<'de> for ValueDeserializer<BinValue> {
160    const SIZE: Option<usize> = None;
161    type Ctx = (ColumnType, ColumnFlags);
162
163    fn deserialize((col_type, col_flags): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
164        let value = Value::deserialize_bin((col_type, col_flags), buf)?;
165        Ok(Self(value, PhantomData))
166    }
167}
168
169/// Will escape string for SQL depending on `no_backslash_escape` flag.
170fn escaped(input: &str, no_backslash_escape: bool) -> String {
171    let mut output = String::with_capacity(input.len());
172    output.push('\'');
173    if no_backslash_escape {
174        for c in input.chars() {
175            if c == '\'' {
176                output.push('\'');
177                output.push('\'');
178            } else {
179                output.push(c);
180            }
181        }
182    } else {
183        for c in input.chars() {
184            if c == '\x00' {
185                output.push('\\');
186                output.push('0');
187            } else if c == '\n' {
188                output.push('\\');
189                output.push('n');
190            } else if c == '\r' {
191                output.push('\\');
192                output.push('r');
193            } else if c == '\\' || c == '\'' || c == '"' {
194                output.push('\\');
195                output.push(c);
196            } else if c == '\x1a' {
197                output.push('\\');
198                output.push('Z');
199            } else {
200                output.push(c);
201            }
202        }
203    }
204    output.push('\'');
205    output
206}
207
208macro_rules! de_num {
209    ($name:ident, $i:ident, $u:ident) => {
210        fn $name(unsigned: bool, buf: &mut ParseBuf<'_>) -> io::Result<Self> {
211            if unsigned {
212                buf.$u()
213                    .ok_or_else(unexpected_buf_eof)
214                    .map(|x| Int(x as i64))
215            } else {
216                buf.$i()
217                    .ok_or_else(unexpected_buf_eof)
218                    .map(|x| Int(x as i64))
219            }
220        }
221    };
222}
223
224impl Value {
225    /// Returns length in binary serialized form.
226    pub fn bin_len(&self) -> u64 {
227        match self {
228            Value::NULL => 0,
229            Value::Bytes(x) => lenenc_str_len(x),
230            Value::Int(_) => 8,
231            Value::UInt(_) => 8,
232            Value::Float(_) => 4,
233            Value::Double(_) => 8,
234            Value::Date(0u16, 0u8, 0u8, 0u8, 0u8, 0u8, 0u32) => 1,
235            Value::Date(_, _, _, 0u8, 0u8, 0u8, 0u32) => 5,
236            Value::Date(_, _, _, _, _, _, 0u32) => 8,
237            Value::Date(_, _, _, _, _, _, _) => 12,
238            Value::Time(_, 0u32, 0u8, 0u8, 0u8, 0u32) => 1,
239            Value::Time(_, _, _, _, _, 0u32) => 9,
240            Value::Time(_, _, _, _, _, _) => 13,
241        }
242    }
243
244    pub fn as_sql(&self, no_backslash_escape: bool) -> String {
245        match *self {
246            Value::NULL => "NULL".into(),
247            Value::Int(x) => format!("{}", x),
248            Value::UInt(x) => format!("{}", x),
249            Value::Float(x) => format!("{}", x),
250            Value::Double(x) => format!("{}", x),
251            Value::Date(y, m, d, 0, 0, 0, 0) => format!("'{:04}-{:02}-{:02}'", y, m, d),
252            Value::Date(year, month, day, hour, minute, second, 0) => format!(
253                "'{:04}-{:02}-{:02} {:02}:{:02}:{:02}'",
254                year, month, day, hour, minute, second
255            ),
256            Value::Date(year, month, day, hour, minute, second, micros) => format!(
257                "'{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:06}'",
258                year, month, day, hour, minute, second, micros
259            ),
260            Value::Time(neg, d, h, i, s, 0) => {
261                if neg {
262                    format!("'-{:03}:{:02}:{:02}'", d * 24 + u32::from(h), i, s)
263                } else {
264                    format!("'{:03}:{:02}:{:02}'", d * 24 + u32::from(h), i, s)
265                }
266            }
267            Value::Time(neg, days, hours, minutes, seconds, micros) => {
268                if neg {
269                    format!(
270                        "'-{:03}:{:02}:{:02}.{:06}'",
271                        days * 24 + u32::from(hours),
272                        minutes,
273                        seconds,
274                        micros
275                    )
276                } else {
277                    format!(
278                        "'{:03}:{:02}:{:02}.{:06}'",
279                        days * 24 + u32::from(hours),
280                        minutes,
281                        seconds,
282                        micros
283                    )
284                }
285            }
286            Value::Bytes(ref bytes) => match from_utf8(bytes) {
287                Ok(string) => escaped(string, no_backslash_escape),
288                Err(_) => {
289                    let mut s = String::from("0x");
290                    for c in bytes.iter() {
291                        s.extend(format!("{:02X}", *c).chars())
292                    }
293                    s
294                }
295            },
296        }
297    }
298
299    fn deserialize_text(buf: &mut ParseBuf<'_>) -> io::Result<Self> {
300        if buf.is_empty() {
301            return Err(unexpected_buf_eof());
302        }
303
304        match buf.0[0] {
305            0xfb => {
306                buf.skip(1);
307                Ok(Value::NULL)
308            }
309            _ => {
310                let bytes: RawBytes<LenEnc> = buf.parse(())?;
311                Ok(Value::Bytes(bytes.0.into_owned()))
312            }
313        }
314    }
315
316    de_num!(deserialize_tiny, checked_eat_i8, checked_eat_u8);
317    de_num!(deserialize_short, checked_eat_i16_le, checked_eat_u16_le);
318    de_num!(deserialize_long, checked_eat_i32_le, checked_eat_u32_le);
319
320    fn deserialize_longlong(unsigned: bool, buf: &mut ParseBuf<'_>) -> io::Result<Self> {
321        if unsigned {
322            buf.checked_eat_u64_le()
323                .ok_or_else(unexpected_buf_eof)
324                .map(|x| i64::try_from(x).map(Int).unwrap_or_else(|_| UInt(x)))
325        } else {
326            buf.checked_eat_i64_le()
327                .ok_or_else(unexpected_buf_eof)
328                .map(Int)
329        }
330    }
331
332    fn deserialize_datetime(buf: &mut ParseBuf<'_>) -> io::Result<Self> {
333        let len = buf.checked_eat_u8().ok_or_else(unexpected_buf_eof)?;
334
335        let mut year = 0u16;
336        let mut month = 0u8;
337        let mut day = 0u8;
338        let mut hour = 0u8;
339        let mut minute = 0u8;
340        let mut second = 0u8;
341        let mut micro_second = 0u32;
342
343        let mut buf = buf
344            .checked_eat_buf(len as usize)
345            .ok_or_else(unexpected_buf_eof)?;
346
347        if len >= 4u8 {
348            year = buf.eat_u16_le();
349            month = buf.eat_u8();
350            day = buf.eat_u8();
351        }
352        if len >= 7u8 {
353            hour = buf.eat_u8();
354            minute = buf.eat_u8();
355            second = buf.eat_u8();
356        }
357        if len == 11u8 {
358            micro_second = buf.eat_u32_le();
359        }
360
361        Ok(Date(year, month, day, hour, minute, second, micro_second))
362    }
363
364    fn deserialize_time(buf: &mut ParseBuf<'_>) -> io::Result<Self> {
365        let len = buf.checked_eat_u8().ok_or_else(unexpected_buf_eof)?;
366
367        let mut is_negative = false;
368        let mut days = 0u32;
369        let mut hours = 0u8;
370        let mut minutes = 0u8;
371        let mut seconds = 0u8;
372        let mut micro_seconds = 0u32;
373
374        let mut buf = buf
375            .checked_eat_buf(len as usize)
376            .ok_or_else(unexpected_buf_eof)?;
377
378        if len >= 8u8 {
379            is_negative = buf.eat_u8() == 1u8;
380            days = buf.eat_u32_le();
381            hours = buf.eat_u8();
382            minutes = buf.eat_u8();
383            seconds = buf.eat_u8();
384        }
385        if len == 12u8 {
386            micro_seconds = buf.eat_u32_le();
387        }
388
389        Ok(Time(
390            is_negative,
391            days,
392            hours,
393            minutes,
394            seconds,
395            micro_seconds,
396        ))
397    }
398
399    pub(crate) fn deserialize_bin(
400        (column_type, column_flags): (ColumnType, ColumnFlags),
401        buf: &mut ParseBuf<'_>,
402    ) -> io::Result<Self> {
403        match column_type {
404            ColumnType::MYSQL_TYPE_STRING
405            | ColumnType::MYSQL_TYPE_VAR_STRING
406            | ColumnType::MYSQL_TYPE_BLOB
407            | ColumnType::MYSQL_TYPE_TINY_BLOB
408            | ColumnType::MYSQL_TYPE_MEDIUM_BLOB
409            | ColumnType::MYSQL_TYPE_LONG_BLOB
410            | ColumnType::MYSQL_TYPE_SET
411            | ColumnType::MYSQL_TYPE_ENUM
412            | ColumnType::MYSQL_TYPE_DECIMAL
413            | ColumnType::MYSQL_TYPE_VARCHAR
414            | ColumnType::MYSQL_TYPE_BIT
415            | ColumnType::MYSQL_TYPE_NEWDECIMAL
416            | ColumnType::MYSQL_TYPE_GEOMETRY
417            | ColumnType::MYSQL_TYPE_VECTOR
418            | ColumnType::MYSQL_TYPE_JSON => Ok(Bytes(
419                buf.checked_eat_lenenc_str()
420                    .ok_or_else(unexpected_buf_eof)?
421                    .to_vec(),
422            )),
423            ColumnType::MYSQL_TYPE_TINY => {
424                Self::deserialize_tiny(column_flags.contains(ColumnFlags::UNSIGNED_FLAG), buf)
425            }
426            ColumnType::MYSQL_TYPE_SHORT | ColumnType::MYSQL_TYPE_YEAR => {
427                Self::deserialize_short(column_flags.contains(ColumnFlags::UNSIGNED_FLAG), buf)
428            }
429            ColumnType::MYSQL_TYPE_LONG | ColumnType::MYSQL_TYPE_INT24 => {
430                Self::deserialize_long(column_flags.contains(ColumnFlags::UNSIGNED_FLAG), buf)
431            }
432            ColumnType::MYSQL_TYPE_LONGLONG => {
433                Self::deserialize_longlong(column_flags.contains(ColumnFlags::UNSIGNED_FLAG), buf)
434            }
435            ColumnType::MYSQL_TYPE_FLOAT => buf
436                .checked_eat_f32_le()
437                .ok_or_else(unexpected_buf_eof)
438                .map(Float),
439            ColumnType::MYSQL_TYPE_DOUBLE => buf
440                .checked_eat_f64_le()
441                .ok_or_else(unexpected_buf_eof)
442                .map(Double),
443            ColumnType::MYSQL_TYPE_TIMESTAMP
444            | ColumnType::MYSQL_TYPE_DATE
445            | ColumnType::MYSQL_TYPE_DATETIME => Self::deserialize_datetime(buf),
446            ColumnType::MYSQL_TYPE_TIME => Self::deserialize_time(buf),
447            ColumnType::MYSQL_TYPE_NULL => Ok(NULL),
448            x => unimplemented!("Unsupported column type {:?}", x),
449        }
450    }
451}
452
453impl fmt::Debug for Value {
454    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
455        match *self {
456            Value::NULL => formatter.debug_tuple("Null").finish(),
457            Value::Bytes(ref bytes) => {
458                let mut debug = formatter.debug_tuple("Bytes");
459                if bytes.len() <= 8 {
460                    debug
461                        .field(&String::from_utf8_lossy(bytes).replace('\n', "\\n"))
462                        .finish()
463                } else {
464                    let bytes = String::from_utf8_lossy(&bytes[..8]).replace('\n', "\\n");
465                    debug.field(&format!("{}..", bytes)).finish()
466                }
467            }
468            Value::Int(ref val) => formatter.debug_tuple("Int").field(val).finish(),
469            Value::UInt(ref val) => formatter.debug_tuple("UInt").field(val).finish(),
470            Value::Float(ref val) => formatter.debug_tuple("Float").field(val).finish(),
471            Value::Double(ref val) => formatter.debug_tuple("Double").field(val).finish(),
472            Value::Date(y, m, d, 0, 0, 0, 0) => {
473                let format = format!("'{:04}-{:02}-{:02}'", y, m, d);
474                formatter.debug_tuple("Date").field(&format).finish()
475            }
476            Value::Date(year, month, day, hour, minute, second, 0) => {
477                let format = format!(
478                    "'{:04}-{:02}-{:02} {:02}:{:02}:{:02}'",
479                    year, month, day, hour, minute, second
480                );
481                formatter.debug_tuple("Date").field(&format).finish()
482            }
483            Value::Date(year, month, day, hour, minute, second, micros) => {
484                let format = format!(
485                    "'{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:06}'",
486                    year, month, day, hour, minute, second, micros
487                );
488                formatter.debug_tuple("Date").field(&format).finish()
489            }
490            Value::Time(neg, d, h, i, s, 0) => {
491                let format = if neg {
492                    format!("'-{:03}:{:02}:{:02}'", d * 24 + u32::from(h), i, s)
493                } else {
494                    format!("'{:03}:{:02}:{:02}'", d * 24 + u32::from(h), i, s)
495                };
496                formatter.debug_tuple("Time").field(&format).finish()
497            }
498            Value::Time(neg, days, hours, minutes, seconds, micros) => {
499                let format = if neg {
500                    format!(
501                        "'-{:03}:{:02}:{:02}.{:06}'",
502                        days * 24 + u32::from(hours),
503                        minutes,
504                        seconds,
505                        micros
506                    )
507                } else {
508                    format!(
509                        "'{:03}:{:02}:{:02}.{:06}'",
510                        days * 24 + u32::from(hours),
511                        minutes,
512                        seconds,
513                        micros
514                    )
515                };
516                formatter.debug_tuple("Time").field(&format).finish()
517            }
518        }
519    }
520}
521
522#[cfg(test)]
523mod test {
524    use std::io;
525
526    use crate::{io::ParseBuf, value::Value};
527
528    #[test]
529    fn should_escape_string() {
530        assert_eq!(r"'?p??\\\\?p??'", Value::from("?p??\\\\?p??").as_sql(false));
531        assert_eq!(r#"'?p??\"?p??'"#, Value::from("?p??\"?p??").as_sql(false));
532        assert_eq!(r"'?p??\'?p??'", Value::from("?p??'?p??").as_sql(false));
533        assert_eq!(r"'?p??\n?p??'", Value::from("?p??\n?p??").as_sql(false));
534        assert_eq!(r"'?p??\r?p??'", Value::from("?p??\r?p??").as_sql(false));
535        assert_eq!(r"'?p??\0?p??'", Value::from("?p??\x00?p??").as_sql(false));
536    }
537
538    #[cfg(feature = "nightly")]
539    mod benches {
540        use std::convert::TryFrom;
541
542        use crate::{
543            constants::ColumnType,
544            io::WriteMysqlExt,
545            packets::{Column, ComStmtExecuteRequestBuilder, NullBitmap},
546            value::{ClientSide, Value},
547        };
548
549        #[bench]
550        fn bench_build_stmt_execute_request(bencher: &mut test::Bencher) {
551            let values = vec![
552                Value::Bytes(b"12.3456789".to_vec()),
553                Value::Int(0xF0),
554                Value::Int(0xF000),
555                Value::Int(0xF0000000),
556                Value::Float(std::f32::MAX),
557                Value::Double(std::f64::MAX),
558                Value::NULL,
559                Value::Date(2019, 11, 27, 12, 30, 0, 123456),
560                Value::UInt(0xF000000000000000),
561                Value::Int(0xF00000),
562                Value::Date(2019, 11, 27, 0, 0, 0, 0),
563                Value::Time(true, 300, 8, 8, 8, 123456),
564                Value::Date(2019, 11, 27, 12, 30, 0, 123456),
565                Value::Int(2019),
566                Value::Bytes(b"varchar".to_vec()),
567                Value::Bytes(b"1000000110000001".to_vec()),
568                Value::Bytes(br#"{"foo":"bar","baz":42345.6777}"#.to_vec()),
569                Value::Bytes(b"12.3456789".to_vec()),
570                Value::Bytes(b"Variant".to_vec()),
571                Value::Bytes(b"Element".to_vec()),
572                Value::Bytes(b"MYSQL_TYPE_TINY_BLOB".to_vec()),
573                Value::Bytes(b"MYSQL_TYPE_MEDIUM_BLOB".to_vec()),
574                Value::Bytes(b"MYSQL_TYPE_LONG_BLOB".to_vec()),
575                Value::Bytes(b"MYSQL_TYPE_BLOB".to_vec()),
576                Value::Bytes(b"MYSQL_TYPE_VAR_STRING".to_vec()),
577                Value::Bytes(b"MYSQL_TYPE_STRING".to_vec()),
578                Value::NULL,
579                Value::Bytes(b"MYSQL_TYPE_GEOMETRY".to_vec()),
580                Value::Bytes(b"MYSQL_TYPE_VECTOR".to_vec()),
581            ];
582
583            let (body, _) = ComStmtExecuteRequestBuilder::new(0).build(&*values);
584
585            bencher.bytes = body.len() as u64;
586            bencher.iter(|| ComStmtExecuteRequestBuilder::new(0).build(&*values));
587        }
588
589        #[cfg(feature = "nightly")]
590        #[bench]
591        fn bench_parse_bin_row(bencher: &mut test::Bencher) {
592            fn col(name: &str, ty: ColumnType) -> Column<'static> {
593                let mut payload = b"\x00def".to_vec();
594                for _ in 0..5 {
595                    payload.write_lenenc_str(name.as_bytes()).unwrap();
596                }
597                payload.extend_from_slice(&b"_\x2d\x00\xff\xff\xff\xff"[..]);
598                payload.push(ty as u8);
599                payload.extend_from_slice(&b"\x00\x00\x00"[..]);
600                Column::read(&payload[..]).unwrap()
601            }
602
603            let values = vec![
604                Value::Bytes(b"12.3456789".to_vec()),
605                Value::Int(0xF0),
606                Value::Int(0xF000),
607                Value::Int(0xF0000000),
608                Value::Float(std::f32::MAX),
609                Value::Double(std::f64::MAX),
610                Value::NULL,
611                Value::Date(2019, 11, 27, 12, 30, 0, 123456),
612                Value::UInt(0xF000000000000000),
613                Value::Int(0xF00000),
614                Value::Date(2019, 11, 27, 0, 0, 0, 0),
615                Value::Time(true, 300, 8, 8, 8, 123456),
616                Value::Date(2019, 11, 27, 12, 30, 0, 123456),
617                Value::Int(2019),
618                Value::Bytes(b"varchar".to_vec()),
619                Value::Bytes(b"1000000110000001".to_vec()),
620                Value::Bytes(br#"{"foo":"bar","baz":42345.6777}"#.to_vec()),
621                Value::Bytes(b"12.3456789".to_vec()),
622                Value::Bytes(b"Variant".to_vec()),
623                Value::Bytes(b"Element".to_vec()),
624                Value::Bytes(b"MYSQL_TYPE_TINY_BLOB".to_vec()),
625                Value::Bytes(b"MYSQL_TYPE_MEDIUM_BLOB".to_vec()),
626                Value::Bytes(b"MYSQL_TYPE_LONG_BLOB".to_vec()),
627                Value::Bytes(b"MYSQL_TYPE_BLOB".to_vec()),
628                Value::Bytes(b"MYSQL_TYPE_VAR_STRING".to_vec()),
629                Value::Bytes(b"MYSQL_TYPE_STRING".to_vec()),
630                Value::NULL,
631                Value::Bytes(b"MYSQL_TYPE_GEOMETRY".to_vec()),
632                Value::Bytes(b"MYSQL_TYPE_VECTOR".to_vec()),
633            ];
634
635            let (body, _) = ComStmtExecuteRequestBuilder::new(0).build(&*values);
636
637            let bitmap_len = NullBitmap::<ClientSide>::bitmap_len(values.len());
638
639            let meta_offset = ComStmtExecuteRequestBuilder::NULL_BITMAP_OFFSET + bitmap_len + 1;
640            let meta_len = values.len() * 2;
641            let columns = body[meta_offset..(meta_offset + meta_len)]
642                .chunks(2)
643                .map(|meta| col("foo", ColumnType::try_from(meta[0]).unwrap()))
644                .collect::<Vec<_>>();
645
646            let mut data = vec![0x00];
647            data.extend_from_slice(
648                &body[ComStmtExecuteRequestBuilder::NULL_BITMAP_OFFSET
649                    ..(ComStmtExecuteRequestBuilder::NULL_BITMAP_OFFSET + bitmap_len)],
650            );
651            data.extend_from_slice(
652                &body[(ComStmtExecuteRequestBuilder::NULL_BITMAP_OFFSET
653                    + bitmap_len
654                    + 1
655                    + 2 * values.len())..],
656            );
657
658            bencher.bytes = data.len() as u64;
659            bencher.iter(|| Value::read_bin_many::<ClientSide>(&*data, &*columns).unwrap());
660        }
661    }
662
663    #[test]
664    fn mysql_simple_issue_284() -> io::Result<()> {
665        use Value::*;
666
667        let mut buf = ParseBuf(&[1, 49, 1, 50, 1, 51, 251, 1, 52, 1, 53, 251, 1, 55][..]);
668        assert_eq!(Value::deserialize_text(&mut buf)?, Bytes(b"1".to_vec()));
669        assert_eq!(Value::deserialize_text(&mut buf)?, Bytes(b"2".to_vec()));
670        assert_eq!(Value::deserialize_text(&mut buf)?, Bytes(b"3".to_vec()));
671        assert_eq!(Value::deserialize_text(&mut buf)?, NULL);
672        assert_eq!(Value::deserialize_text(&mut buf)?, Bytes(b"4".to_vec()));
673        assert_eq!(Value::deserialize_text(&mut buf)?, Bytes(b"5".to_vec()));
674        assert_eq!(Value::deserialize_text(&mut buf)?, NULL);
675        assert_eq!(Value::deserialize_text(&mut buf)?, Bytes(b"7".to_vec()));
676
677        Ok(())
678    }
679}