zero_postgres/protocol/backend/
query.rs1use std::mem::size_of;
4
5use zerocopy::byteorder::big_endian::{I16 as I16BE, I32 as I32BE, U16 as U16BE, U32 as U32BE};
6use zerocopy::{FromBytes, Immutable, KnownLayout};
7
8use crate::error::{Error, Result};
9use crate::protocol::codec::read_cstr;
10use crate::protocol::types::{FormatCode, Oid};
11
12#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable)]
14#[repr(C, packed)]
15pub struct FieldDescriptionTail {
16 pub table_oid: U32BE,
18 pub column_id: I16BE,
20 pub type_oid: U32BE,
22 pub type_size: I16BE,
24 pub type_modifier: I32BE,
26 pub format: U16BE,
28}
29
30#[derive(Debug, Clone, Copy)]
32pub struct FieldDescription<'a> {
33 pub name: &'a str,
35 pub tail: &'a FieldDescriptionTail,
37}
38
39impl FieldDescription<'_> {
40 pub fn table_oid(&self) -> Oid {
42 self.tail.table_oid.get()
43 }
44
45 pub fn column_id(&self) -> i16 {
47 self.tail.column_id.get()
48 }
49
50 pub fn type_oid(&self) -> Oid {
52 self.tail.type_oid.get()
53 }
54
55 pub fn type_size(&self) -> i16 {
57 self.tail.type_size.get()
58 }
59
60 pub fn type_modifier(&self) -> i32 {
62 self.tail.type_modifier.get()
63 }
64
65 pub fn format(&self) -> FormatCode {
67 FormatCode::from_u16(self.tail.format.get())
68 }
69}
70
71#[derive(Debug)]
73pub struct RowDescription<'a> {
74 fields: Vec<FieldDescription<'a>>,
75}
76
77impl<'a> RowDescription<'a> {
78 pub fn parse(payload: &'a [u8]) -> Result<Self> {
80 let num_fields = U16BE::ref_from_bytes(&payload[..2])
81 .map_err(|e| Error::LibraryBug(format!("RowDescription header: {e:?}")))?
82 .get() as usize;
83 let mut fields = Vec::with_capacity(num_fields);
84 let mut data = &payload[2..];
85
86 const TAIL_SIZE: usize = size_of::<FieldDescriptionTail>();
87
88 for _ in 0..num_fields {
89 let (name, rest) = read_cstr(data)?;
90 let tail = FieldDescriptionTail::ref_from_bytes(&rest[..TAIL_SIZE])
91 .map_err(|e| Error::LibraryBug(format!("FieldDescription tail: {e:?}")))?;
92
93 fields.push(FieldDescription { name, tail });
94
95 data = &rest[TAIL_SIZE..];
96 }
97
98 Ok(Self { fields })
99 }
100
101 pub fn len(&self) -> usize {
103 self.fields.len()
104 }
105
106 pub fn is_empty(&self) -> bool {
108 self.fields.is_empty()
109 }
110
111 pub fn fields(&self) -> &[FieldDescription<'a>] {
113 &self.fields
114 }
115
116 pub fn iter(&self) -> impl Iterator<Item = &FieldDescription<'a>> {
118 self.fields.iter()
119 }
120}
121
122#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable)]
124#[repr(C, packed)]
125pub struct DataRowHead {
126 pub num_columns: U16BE,
128}
129
130#[derive(Debug, Clone, Copy)]
132pub struct DataRow<'a> {
133 num_columns: u16,
135 columns_data: &'a [u8],
137}
138
139impl<'a> DataRow<'a> {
140 pub fn parse(payload: &'a [u8]) -> Result<Self> {
142 let head = DataRowHead::ref_from_bytes(&payload[..2])
143 .map_err(|e| Error::LibraryBug(format!("DataRow header: {e:?}")))?;
144
145 Ok(Self {
146 num_columns: head.num_columns.get(),
147 columns_data: &payload[2..],
148 })
149 }
150
151 pub fn len(&self) -> usize {
153 self.num_columns as usize
154 }
155
156 pub fn is_empty(&self) -> bool {
158 self.num_columns == 0
159 }
160
161 pub fn iter(&self) -> DataRowIter<'a> {
165 DataRowIter {
166 remaining: self.columns_data,
167 }
168 }
169
170 pub fn get(&self, index: usize) -> Option<Option<&'a [u8]>> {
174 self.iter().nth(index)
175 }
176
177 pub fn raw_data(&self) -> &'a [u8] {
182 self.columns_data
183 }
184}
185
186#[derive(Debug, Clone)]
188pub struct DataRowIter<'a> {
189 remaining: &'a [u8],
190}
191
192impl<'a> Iterator for DataRowIter<'a> {
193 type Item = Option<&'a [u8]>;
194
195 fn next(&mut self) -> Option<Self::Item> {
196 let (len_bytes, remaining) = self.remaining.split_first_chunk::<4>()?;
197 self.remaining = remaining;
198 let len = i32::from_be_bytes(*len_bytes);
199
200 if len == -1 {
201 Some(None)
203 } else {
204 let len = len as usize;
205 if self.remaining.len() < len {
206 return None;
207 }
208
209 let value;
210 (value, self.remaining) = self.remaining.split_at_checked(len)?;
211 Some(Some(value))
212 }
213 }
214}
215
216#[derive(Debug, Clone, Copy)]
218pub struct CommandComplete<'a> {
219 pub tag: &'a str,
221}
222
223impl<'a> CommandComplete<'a> {
224 pub fn parse(payload: &'a [u8]) -> Result<Self> {
226 let (tag, _) = read_cstr(payload)?;
227 Ok(Self { tag })
228 }
229
230 pub fn rows_affected(&self) -> Option<u64> {
235 let mut iter = self.tag.split_whitespace();
242 match iter.next()? {
243 "SELECT" | "UPDATE" | "DELETE" | "COPY" | "MOVE" | "FETCH" => (),
244 "INSERT" => _ = iter.next(), _ => return None,
246 }
247 iter.next()?.parse().ok()
248 }
249
250 pub fn command(&self) -> Option<&str> {
252 self.tag.split_whitespace().next()
253 }
254}
255
256#[derive(Debug, Clone, Copy)]
258pub struct EmptyQueryResponse;
259
260impl EmptyQueryResponse {
261 pub fn parse(_payload: &[u8]) -> Result<Self> {
263 Ok(Self)
264 }
265}