sqlx_postgres/
value.rs

1use crate::error::{BoxDynError, UnexpectedNullError};
2use crate::{PgTypeInfo, Postgres};
3use sqlx_core::bytes::{Buf, Bytes};
4pub(crate) use sqlx_core::value::{Value, ValueRef};
5use std::borrow::Cow;
6use std::str::from_utf8;
7
8#[derive(Debug, Clone, Copy, Eq, PartialEq)]
9#[repr(u8)]
10pub enum PgValueFormat {
11    Text = 0,
12    Binary = 1,
13}
14
15/// Implementation of [`ValueRef`] for PostgreSQL.
16#[derive(Clone)]
17pub struct PgValueRef<'r> {
18    pub(crate) value: Option<&'r [u8]>,
19    pub(crate) row: Option<&'r Bytes>,
20    pub(crate) type_info: PgTypeInfo,
21    pub(crate) format: PgValueFormat,
22}
23
24/// Implementation of [`Value`] for PostgreSQL.
25#[derive(Clone)]
26pub struct PgValue {
27    pub(crate) value: Option<Bytes>,
28    pub(crate) type_info: PgTypeInfo,
29    pub(crate) format: PgValueFormat,
30}
31
32impl<'r> PgValueRef<'r> {
33    pub(crate) fn get(
34        buf: &mut &'r [u8],
35        format: PgValueFormat,
36        ty: PgTypeInfo,
37    ) -> Result<Self, String> {
38        let element_len = buf.get_i32();
39
40        let element_val = if element_len == -1 {
41            None
42        } else {
43            let element_len: usize = element_len
44                .try_into()
45                .map_err(|_| format!("overflow converting element_len ({element_len}) to usize"))?;
46
47            let val = &buf[..element_len];
48            buf.advance(element_len);
49            Some(val)
50        };
51
52        Ok(PgValueRef {
53            value: element_val,
54            row: None,
55            type_info: ty,
56            format,
57        })
58    }
59
60    pub fn format(&self) -> PgValueFormat {
61        self.format
62    }
63
64    pub fn as_bytes(&self) -> Result<&'r [u8], BoxDynError> {
65        match &self.value {
66            Some(v) => Ok(v),
67            None => Err(UnexpectedNullError.into()),
68        }
69    }
70
71    pub fn as_str(&self) -> Result<&'r str, BoxDynError> {
72        Ok(from_utf8(self.as_bytes()?)?)
73    }
74}
75
76impl Value for PgValue {
77    type Database = Postgres;
78
79    #[inline]
80    fn as_ref(&self) -> PgValueRef<'_> {
81        PgValueRef {
82            value: self.value.as_deref(),
83            row: None,
84            type_info: self.type_info.clone(),
85            format: self.format,
86        }
87    }
88
89    fn type_info(&self) -> Cow<'_, PgTypeInfo> {
90        Cow::Borrowed(&self.type_info)
91    }
92
93    fn is_null(&self) -> bool {
94        self.value.is_none()
95    }
96}
97
98impl<'r> ValueRef<'r> for PgValueRef<'r> {
99    type Database = Postgres;
100
101    fn to_owned(&self) -> PgValue {
102        let value = match (self.row, self.value) {
103            (Some(row), Some(value)) => Some(row.slice_ref(value)),
104
105            (None, Some(value)) => Some(Bytes::copy_from_slice(value)),
106
107            _ => None,
108        };
109
110        PgValue {
111            value,
112            format: self.format,
113            type_info: self.type_info.clone(),
114        }
115    }
116
117    fn type_info(&self) -> Cow<'_, PgTypeInfo> {
118        Cow::Borrowed(&self.type_info)
119    }
120
121    fn is_null(&self) -> bool {
122        self.value.is_none()
123    }
124}