mysql_common/binlog/
misc.rs

1// Copyright (c) 2020 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 byteorder::{BigEndian as BE, ReadBytesExt};
10use saturating::Saturating as S;
11
12use std::{
13    cmp::min,
14    io::{self, Write},
15};
16
17use crate::value::Value;
18
19pub const TIMEF_INT_OFS: i64 = 0x800000;
20pub const TIMEF_OFS: i64 = 0x800000000000;
21pub const DATETIMEF_INT_OFS: i64 = 0x8000000000;
22
23pub fn my_packed_time_make_int(i: i64) -> i64 {
24    ((i as u64) << 24) as i64
25}
26
27pub fn my_packed_time_make(i: i64, f: i64) -> i64 {
28    ((i as u64) << 24) as i64 + f
29}
30
31pub fn my_time_packed_from_binary<T: io::Read>(mut input: T, dec: u32) -> io::Result<i64> {
32    match dec {
33        1 | 2 => {
34            let mut intpart = input.read_u24::<BE>()? as i64 - TIMEF_INT_OFS;
35            let mut frac = input.read_u8()? as u32;
36            if intpart < 0 && frac > 0 {
37                intpart += 1;
38                frac -= 0x100;
39            }
40            Ok(my_packed_time_make(intpart, (frac as i64) * 10_000))
41        }
42        3 | 4 => {
43            let mut intpart = input.read_u24::<BE>()? as i64 - TIMEF_INT_OFS;
44            let mut frac = input.read_u16::<BE>()? as i32;
45            if intpart < 0 && frac > 0 {
46                intpart += 1;
47                frac -= 0x10000;
48            }
49            Ok(my_packed_time_make(intpart, (frac * 100) as i64))
50        }
51        5 | 6 => Ok((input.read_u48::<BE>()? as i64) - TIMEF_OFS),
52        _ => {
53            let i = input.read_u24::<BE>()? as i64 - TIMEF_INT_OFS;
54            Ok(my_packed_time_make_int(i))
55        }
56    }
57}
58
59pub fn my_packed_time_get_int_part(i: i64) -> i64 {
60    i >> 24
61}
62
63pub fn my_packed_time_get_frac_part(i: i64) -> i64 {
64    i % (1 << 24)
65}
66
67pub fn time_from_packed(mut tmp: i64) -> Value {
68    let neg = if tmp < 0 {
69        tmp = -tmp;
70        true
71    } else {
72        false
73    };
74    let hms = my_packed_time_get_int_part(tmp);
75    let h = ((hms >> 12) as u32) % (1 << 10);
76    let m = ((hms >> 6) as u32) % (1 << 6);
77    let s = ((hms) as u32) % (1 << 6);
78    let u = my_packed_time_get_frac_part(tmp);
79    Value::Time(neg, 0, h as u8, m as u8, s as u8, u as u32)
80}
81
82pub fn my_datetime_packed_from_binary<T: io::Read>(mut input: T, dec: u32) -> io::Result<i64> {
83    let intpart = (input.read_uint::<BE>(5)? as i64) - DATETIMEF_INT_OFS;
84    let frac = match dec {
85        1 | 2 => (input.read_i8()? as i32) * 10_000,
86        3 | 4 => (input.read_i16::<BE>()? as i32) * 100,
87        5 | 6 => input.read_i24::<BE>()?,
88        _ => return Ok(my_packed_time_make_int(intpart)),
89    };
90    Ok(my_packed_time_make(intpart, frac as i64))
91}
92
93pub fn datetime_from_packed(mut tmp: i64) -> Value {
94    if tmp < 0 {
95        tmp = -tmp;
96    }
97    let usec = my_packed_time_get_frac_part(tmp);
98    let ymdhms = my_packed_time_get_int_part(tmp);
99
100    let ymd = ymdhms >> 17;
101    let ym = ymd >> 5;
102    let hms = ymdhms % (1 << 17);
103
104    let day = ymd % (1 << 5);
105    let mon = ym % 13;
106    let year = (ym / 13) as u32;
107
108    let sec = hms % (1 << 6);
109    let min = (hms >> 6) % (1 << 6);
110    let hour = (hms >> 12) as u32;
111
112    Value::Date(
113        year as u16,
114        mon as u8,
115        day as u8,
116        hour as u8,
117        min as u8,
118        sec as u8,
119        usec as u32,
120    )
121}
122
123pub fn my_timestamp_from_binary<T: io::Read>(mut input: T, dec: u8) -> io::Result<(i32, i32)> {
124    let sec = input.read_u32::<BE>()? as i32;
125    let usec = match dec {
126        1 | 2 => input.read_i8()? as i32 * 10000,
127        3 | 4 => input.read_i16::<BE>()? as i32 * 100,
128        5 | 6 => input.read_i24::<BE>()?,
129        _ => 0,
130    };
131    Ok((sec, usec))
132}
133
134pub(crate) struct LimitedWrite<T> {
135    limit: S<usize>,
136    write: T,
137}
138
139impl<T> LimitedWrite<T> {
140    pub fn new(write: T, limit: S<usize>) -> Self {
141        Self { limit, write }
142    }
143}
144
145impl<T: Write> Write for LimitedWrite<T> {
146    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
147        let limit = min(buf.len(), self.limit.0);
148        let count = self.write.write(&buf[..limit])?;
149        self.limit -= S(count);
150        Ok(count)
151    }
152
153    fn flush(&mut self) -> io::Result<()> {
154        self.write.flush()
155    }
156}
157
158pub(crate) trait LimitWrite: Write + Sized {
159    fn limit(&mut self, limit: S<usize>) -> LimitedWrite<&mut Self> {
160        LimitedWrite::new(self, limit)
161    }
162}
163
164impl<T: Write> LimitWrite for T {}