mz_pgrepr/value/
record.rs
1use std::error::Error;
14
15use postgres_types::{FromSql, Kind, Type, WrongType, private};
16
17#[derive(Debug, PartialEq, Eq)]
20pub struct Record<T>(pub T);
21
22macro_rules! impl_tuple {
23 ($n:expr; $($ty_ident:ident),*; $($var_ident:ident),*) => {
24 impl<'a, $($ty_ident),*> FromSql<'a> for Record<($($ty_ident,)*)>
25 where
26 $($ty_ident: FromSql<'a>),*
27 {
28 fn from_sql(
29 _: &Type,
30 mut raw: &'a [u8],
31 ) -> Result<Record<($($ty_ident,)*)>, Box<dyn Error + Sync + Send>> {
32 let num_fields = private::read_be_i32(&mut raw)?;
33 let num_fields = u32::try_from(num_fields).map_err(|_| format!("number of fields cannot be negative: {}", num_fields))?;
34 if num_fields != $n {
35 return Err(format!(
36 "Postgres record field count does not match Rust tuple length: {} vs {}",
37 num_fields,
38 $n,
39 ).into());
40 }
41
42 $(
43 let oid = private::read_be_i32(&mut raw)?;
44 let oid = u32::try_from(oid).map_err(|_| format!("OIDs cannot be negative: {}", oid))?;
45 let ty = match Type::from_oid(oid) {
46 None => {
47 return Err(format!(
48 "cannot decode OID {} inside of anonymous record",
49 oid,
50 ).into());
51 }
52 Some(ty) if !$ty_ident::accepts(&ty) => {
53 return Err(Box::new(WrongType::new::<$ty_ident>(ty.clone())));
54 }
55 Some(ty) => ty,
56 };
57 let $var_ident = private::read_value(&ty, &mut raw)?;
58 )*
59
60 Ok(Record(($($var_ident,)*)))
61 }
62
63 fn accepts(ty: &Type) -> bool {
64 match ty.kind() {
65 Kind::Pseudo => *ty == Type::RECORD,
66 Kind::Composite(fields) => fields.len() == $n,
67 _ => false,
68 }
69 }
70 }
71 };
72}
73
74impl_tuple!(0; ; );
75impl_tuple!(1; T0; v0);
76impl_tuple!(2; T0, T1; v0, v1);
77impl_tuple!(3; T0, T1, T2; v0, v1, v2);
78impl_tuple!(4; T0, T1, T2, T3; v0, v1, v2, v3);