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::Protocol(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::Protocol(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::Protocol(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
178#[derive(Debug, Clone)]
180pub struct DataRowIter<'a> {
181 remaining: &'a [u8],
182}
183
184impl<'a> Iterator for DataRowIter<'a> {
185 type Item = Option<&'a [u8]>;
186
187 fn next(&mut self) -> Option<Self::Item> {
188 let len;
189 (len, self.remaining) = self.remaining.split_at_checked(4)?;
190 let len = i32::from_be_bytes([len[0], len[1], len[2], len[3]]);
191
192 if len == -1 {
193 Some(None)
195 } else {
196 let len = len as usize;
197 if self.remaining.len() < len {
198 return None;
199 }
200
201 let value;
202 (value, self.remaining) = self.remaining.split_at_checked(len)?;
203 Some(Some(value))
204 }
205 }
206}
207
208#[derive(Debug, Clone, Copy)]
210pub struct CommandComplete<'a> {
211 pub tag: &'a str,
213}
214
215impl<'a> CommandComplete<'a> {
216 pub fn parse(payload: &'a [u8]) -> Result<Self> {
218 let (tag, _) = read_cstr(payload)?;
219 Ok(Self { tag })
220 }
221
222 pub fn rows_affected(&self) -> Option<u64> {
227 let parts: Vec<&str> = self.tag.split_whitespace().collect();
234
235 match parts.as_slice() {
236 ["SELECT", count] => count.parse().ok(),
237 ["INSERT", _oid, count] => count.parse().ok(),
238 ["UPDATE", count] => count.parse().ok(),
239 ["DELETE", count] => count.parse().ok(),
240 ["COPY", count] => count.parse().ok(),
241 ["MOVE", count] => count.parse().ok(),
242 ["FETCH", count] => count.parse().ok(),
243 _ => None,
244 }
245 }
246
247 pub fn command(&self) -> Option<&str> {
249 self.tag.split_whitespace().next()
250 }
251}
252
253#[derive(Debug, Clone, Copy)]
255pub struct EmptyQueryResponse;
256
257impl EmptyQueryResponse {
258 pub fn parse(_payload: &[u8]) -> Result<Self> {
260 Ok(Self)
261 }
262}