sqlx_postgres/message/
row_description.rs

1use sqlx_core::bytes::{Buf, Bytes};
2
3use crate::error::Error;
4use crate::io::BufExt;
5use crate::message::{BackendMessage, BackendMessageFormat};
6use crate::types::Oid;
7
8#[derive(Debug)]
9pub struct RowDescription {
10    pub fields: Vec<Field>,
11}
12
13#[derive(Debug)]
14pub struct Field {
15    /// The name of the field.
16    pub name: String,
17
18    /// If the field can be identified as a column of a specific table, the
19    /// object ID of the table; otherwise zero.
20    pub relation_id: Option<Oid>,
21
22    /// If the field can be identified as a column of a specific table, the attribute number of
23    /// the column; otherwise zero.
24    pub relation_attribute_no: Option<i16>,
25
26    /// The object ID of the field's data type.
27    pub data_type_id: Oid,
28
29    /// The data type size (see pg_type.typlen). Note that negative values denote
30    /// variable-width types.
31    #[allow(dead_code)]
32    pub data_type_size: i16,
33
34    /// The type modifier (see pg_attribute.atttypmod). The meaning of the
35    /// modifier is type-specific.
36    #[allow(dead_code)]
37    pub type_modifier: i32,
38
39    /// The format code being used for the field.
40    #[allow(dead_code)]
41    pub format: i16,
42}
43
44impl BackendMessage for RowDescription {
45    const FORMAT: BackendMessageFormat = BackendMessageFormat::RowDescription;
46
47    fn decode_body(mut buf: Bytes) -> Result<Self, Error> {
48        if buf.len() < 2 {
49            return Err(err_protocol!(
50                "expected at least 2 bytes, got {}",
51                buf.len()
52            ));
53        }
54
55        let cnt = buf.get_u16();
56        let mut fields = Vec::with_capacity(cnt as usize);
57
58        for _ in 0..cnt {
59            let name = buf.get_str_nul()?.to_owned();
60
61            if buf.len() < 18 {
62                return Err(err_protocol!(
63                    "expected at least 18 bytes after field name {name:?}, got {}",
64                    buf.len()
65                ));
66            }
67
68            let relation_id = buf.get_u32();
69            let relation_attribute_no = buf.get_i16();
70            let data_type_id = Oid(buf.get_u32());
71            let data_type_size = buf.get_i16();
72            let type_modifier = buf.get_i32();
73            let format = buf.get_i16();
74
75            fields.push(Field {
76                name,
77                relation_id: if relation_id == 0 {
78                    None
79                } else {
80                    Some(Oid(relation_id))
81                },
82                relation_attribute_no: if relation_attribute_no == 0 {
83                    None
84                } else {
85                    Some(relation_attribute_no)
86                },
87                data_type_id,
88                data_type_size,
89                type_modifier,
90                format,
91            })
92        }
93
94        Ok(Self { fields })
95    }
96}
97
98// TODO: Unit Test RowDescription
99// TODO: Benchmark RowDescription