cdbc_mysql/
value.rs

1use cdbc::error::{BoxDynError, UnexpectedNullError};
2use crate::protocol::text::ColumnType;
3use crate::{MySql, MySqlTypeInfo};
4use cdbc::value::{Value, ValueRef};
5use bytes::Bytes;
6use std::borrow::Cow;
7use std::str::from_utf8;
8
9#[derive(Debug, Clone, Copy)]
10#[repr(u8)]
11pub enum MySqlValueFormat {
12    Text,
13    Binary,
14}
15
16/// Implementation of [`Value`] for MySQL.
17#[derive(Clone)]
18pub struct MySqlValue {
19    value: Option<Bytes>,
20    type_info: MySqlTypeInfo,
21    format: MySqlValueFormat,
22}
23
24/// Implementation of [`ValueRef`] for MySQL.
25#[derive(Clone)]
26pub struct MySqlValueRef<'r> {
27    pub(crate) value: Option<&'r [u8]>,
28    pub(crate) row: Option<&'r Bytes>,
29    pub(crate) type_info: MySqlTypeInfo,
30    pub(crate) format: MySqlValueFormat,
31}
32
33impl<'r> MySqlValueRef<'r> {
34    pub(crate) fn format(&self) -> MySqlValueFormat {
35        self.format
36    }
37
38    pub(crate) fn as_bytes(&self) -> Result<&'r [u8], BoxDynError> {
39        match &self.value {
40            Some(v) => Ok(v),
41            None => Err(UnexpectedNullError.into()),
42        }
43    }
44
45    pub(crate) fn as_str(&self) -> Result<&'r str, BoxDynError> {
46        Ok(from_utf8(self.as_bytes()?)?)
47    }
48}
49
50impl Value for MySqlValue {
51    type Database = MySql;
52
53    fn as_ref(&self) -> MySqlValueRef<'_> {
54        MySqlValueRef {
55            value: self.value.as_deref(),
56            row: None,
57            type_info: self.type_info.clone(),
58            format: self.format,
59        }
60    }
61
62    fn type_info(&self) -> Cow<'_, MySqlTypeInfo> {
63        Cow::Borrowed(&self.type_info)
64    }
65
66    fn is_null(&self) -> bool {
67        is_null(self.value.as_deref(), &self.type_info)
68    }
69}
70
71impl<'r> ValueRef<'r> for MySqlValueRef<'r> {
72    type Database = MySql;
73
74    fn to_owned(&self) -> MySqlValue {
75        let value = match (self.row, self.value) {
76            (Some(row), Some(value)) => Some(row.slice_ref(value)),
77
78            (None, Some(value)) => Some(Bytes::copy_from_slice(value)),
79
80            _ => None,
81        };
82
83        MySqlValue {
84            value,
85            format: self.format,
86            type_info: self.type_info.clone(),
87        }
88    }
89
90    fn type_info(&self) -> Cow<'_, MySqlTypeInfo> {
91        Cow::Borrowed(&self.type_info)
92    }
93
94    #[inline]
95    fn is_null(&self) -> bool {
96        is_null(self.value.as_deref(), &self.type_info)
97    }
98}
99
100fn is_null(value: Option<&[u8]>, ty: &MySqlTypeInfo) -> bool {
101    if let Some(value) = value {
102        // zero dates and date times should be treated the same as NULL
103        if matches!(
104            ty.r#type,
105            ColumnType::Date | ColumnType::Timestamp | ColumnType::Datetime
106        ) && value.get(0) == Some(&0)
107        {
108            return true;
109        }
110    }
111
112    value.is_none()
113}