rbdc_mysql/types/
decode.rs

1use crate::protocol::text::ColumnType;
2use crate::value::{MySqlValue, MySqlValueFormat};
3use byteorder::{ByteOrder, LittleEndian};
4use bytes::Buf;
5use fastdate::Date;
6use rbdc::Error;
7
8pub(crate) fn uint_decode(value: MySqlValue) -> Result<u64, Error> {
9    if value.type_info.r#type == ColumnType::Bit {
10        // NOTE: Regardless of the value format, there is raw binary data here
11        let buf = value.as_bytes()?;
12        let mut value: u64 = 0;
13        for b in buf {
14            value = (*b as u64) | (value << 8);
15        }
16        return Ok(value);
17    }
18
19    Ok(match value.format() {
20        MySqlValueFormat::Text => value.as_str()?.parse().unwrap_or_default(),
21
22        MySqlValueFormat::Binary => {
23            let buf = value.as_bytes()?;
24            LittleEndian::read_uint(buf, buf.len())
25        }
26    })
27}
28
29pub(crate) fn int_decode(value: MySqlValue) -> Result<i64, Error> {
30    Ok(match value.format() {
31        MySqlValueFormat::Text => value.as_str()?.parse().unwrap_or_default(),
32        MySqlValueFormat::Binary => {
33            let buf = value.as_bytes()?;
34            LittleEndian::read_int(buf, buf.len())
35        }
36    })
37}
38
39pub(crate) fn f32_decode(value: MySqlValue) -> Result<f32, Error> {
40    Ok(match value.format() {
41        MySqlValueFormat::Binary => {
42            let buf = value.as_bytes()?;
43
44            if buf.len() == 8 {
45                // MySQL can return 8-byte DOUBLE values for a FLOAT
46                // We take and truncate to f32 as that's the same behavior as *in* MySQL
47                LittleEndian::read_f64(buf) as f32
48            } else {
49                LittleEndian::read_f32(buf)
50            }
51        }
52
53        MySqlValueFormat::Text => value.as_str()?.parse().unwrap_or_default(),
54    })
55}
56
57pub(crate) fn f64_decode(value: MySqlValue) -> Result<f64, Error> {
58    Ok(match value.format() {
59        MySqlValueFormat::Binary => LittleEndian::read_f64(value.as_bytes()?),
60        MySqlValueFormat::Text => value.as_str()?.parse().unwrap_or_default(),
61    })
62}
63
64pub(crate) fn decode_timestamp(value: MySqlValue) -> Result<String, Error> {
65    Ok(match value.format() {
66        MySqlValueFormat::Text => {
67            let mut v = value.as_str()?.to_string();
68            if !v.ends_with("Z") {
69                v.push_str("Z");
70            }
71            v
72        }
73        MySqlValueFormat::Binary => {
74            let buf = value.as_bytes()?;
75            let len = buf[0];
76            let date = decode_date_buf(&buf[1..])?.to_string();
77            let dt = if len > 4 {
78                decode_time_buf(len - 4, &buf[5..])?
79            } else {
80                "00:00:00".to_string()
81            };
82            date + " " + &dt + "Z"
83        }
84    })
85}
86
87pub(crate) fn decode_year(value: MySqlValue) -> Result<String, Error> {
88    Ok(match value.format() {
89        MySqlValueFormat::Text => value.as_str()?.to_string(),
90        MySqlValueFormat::Binary => {
91            let buf = value.as_bytes()?;
92            let date = decode_year_buf(&buf[1..])?;
93            date
94        }
95    })
96}
97
98pub(crate) fn decode_date(value: MySqlValue) -> Result<String, Error> {
99    Ok(match value.format() {
100        MySqlValueFormat::Text => value.as_str()?.to_string(),
101        MySqlValueFormat::Binary => {
102            let buf = value.as_bytes()?;
103            let date = decode_date_buf(&buf[1..])?.to_string();
104            date
105        }
106    })
107}
108
109pub(crate) fn decode_time(value: MySqlValue) -> Result<String, Error> {
110    Ok(match value.format() {
111        MySqlValueFormat::Text => value.as_str()?.to_string(),
112        MySqlValueFormat::Binary => {
113            let buf = value.as_bytes()?;
114            let len = buf[0];
115            let dt = if len > 4 {
116                decode_time_buf(len - 4, &buf[5..])?
117            } else {
118                "00:00:00".to_string()
119            };
120            dt
121        }
122    })
123}
124
125pub(crate) fn decode_date_buf(buf: &[u8]) -> Result<Date, Error> {
126    if buf.is_empty() {
127        // zero buffer means a zero date (null)
128        return Ok(Date {
129            year: 0000,
130            mon: 00,
131            day: 00,
132        });
133    }
134    Ok(Date {
135        year: LittleEndian::read_u16(buf) as i32,
136        mon: buf[2] as u8,
137        day: buf[3] as u8,
138    })
139}
140
141pub(crate) fn decode_year_buf(buf: &[u8]) -> Result<String, Error> {
142    if buf.is_empty() {
143        // zero buffer means a zero date (null)
144        return Ok("".to_string());
145    }
146    Ok(format!("{:0>4}", LittleEndian::read_u16(buf) as i32,))
147}
148
149pub(crate) fn decode_time_buf(_: u8, mut buf: &[u8]) -> Result<String, Error> {
150    let hour = buf.get_u8();
151    let minute = buf.get_u8();
152    let seconds = buf.get_u8();
153    let milliseconds = if buf.len() >= 4 {
154        buf.get_u32_le()
155    } else {
156        0 // 如果没有足够的字节表示毫秒值,将其设置为默认值
157    };
158    Ok(format!(
159        "{:0>2}:{:0>2}:{:0>2}.{:0>6}",
160        hour, minute, seconds, milliseconds
161    ))
162}
163
164pub(crate) fn decode_bool(value: MySqlValue) -> Result<bool, Error> {
165    Ok(int_decode(value)? != 0)
166}