elefant_client/types/
binary.rs1use crate::protocol::FieldDescription;
2use crate::types::{FromSqlBase, FromSqlBinary, FromSqlText, PostgresNamedType, ToSql};
3use crate::PostgresType;
4use std::error::Error;
5
6impl<'a> FromSqlBase<'a> for Vec<u8> {
7 fn accepts_postgres_type(oid: i32) -> bool {
8 oid == PostgresType::BYTEA.oid
9 }
10}
11
12impl<'a> FromSqlBinary<'a> for Vec<u8> {
13 fn from_sql_binary(
14 raw: &'a [u8],
15 _field: &FieldDescription,
16 ) -> Result<Self, Box<dyn Error + Sync + Send>> {
17 Ok(raw.to_vec())
18 }
19}
20
21impl<'a> FromSqlText<'a> for Vec<u8> {
22 fn from_sql_text(
23 raw: &'a str,
24 _field: &FieldDescription,
25 ) -> Result<Self, Box<dyn Error + Sync + Send>> {
26 let hex_str = if let Some(stripped) = raw.strip_prefix("\\x") {
29 stripped
30 } else if raw.starts_with("\"\\\\x") && raw.ends_with("\"") {
31 &raw[4..raw.len() - 1]
33 } else if let Some(stripped) = raw.strip_prefix("\\\\x") {
34 stripped
36 } else {
37 let mut result = Vec::with_capacity(raw.len() / 2);
40 for chunk in raw.as_bytes().chunks(2) {
41 if chunk.len() == 2 {
42 let hex_byte = std::str::from_utf8(chunk)?;
43 if let Ok(byte) = u8::from_str_radix(hex_byte, 16) {
44 result.push(byte);
45 } else {
46 return Ok(raw.as_bytes().to_vec());
48 }
49 } else {
50 return Ok(raw.as_bytes().to_vec());
52 }
53 }
54 return Ok(result);
55 };
56
57 let mut result = Vec::with_capacity(hex_str.len() / 2);
58
59 for chunk in hex_str.as_bytes().chunks(2) {
60 if chunk.len() == 2 {
61 let hex_byte = std::str::from_utf8(chunk)?;
62 let byte = u8::from_str_radix(hex_byte, 16)
63 .map_err(|e| format!("Invalid hex byte '{hex_byte}': {e}"))?;
64 result.push(byte);
65 }
66 }
67 Ok(result)
68 }
69}
70
71impl ToSql for Vec<u8> {
72 fn to_sql_binary(
73 &self,
74 target_buffer: &mut Vec<u8>,
75 ) -> Result<(), Box<dyn Error + Sync + Send>> {
76 target_buffer.extend_from_slice(self);
77 Ok(())
78 }
79}
80
81impl PostgresNamedType for Vec<u8> {
82 const PG_NAME: &'static str = PostgresType::BYTEA.name;
83}
84
85impl<'a> FromSqlBase<'a> for &'a [u8] {
86 fn accepts_postgres_type(oid: i32) -> bool {
87 oid == PostgresType::BYTEA.oid
88 }
89}
90
91impl<'a> FromSqlBinary<'a> for &'a [u8] {
92 fn from_sql_binary(
93 raw: &'a [u8],
94 _field: &FieldDescription,
95 ) -> Result<Self, Box<dyn Error + Sync + Send>> {
96 Ok(raw)
97 }
98}
99
100impl ToSql for &[u8] {
105 fn to_sql_binary(
106 &self,
107 target_buffer: &mut Vec<u8>,
108 ) -> Result<(), Box<dyn Error + Sync + Send>> {
109 target_buffer.extend_from_slice(self);
110 Ok(())
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 #[cfg(feature = "tokio")]
117 mod tokio_connection {
118 use crate::test_helpers::get_settings;
119 use crate::tokio_connection::new_client;
120 use tokio::test;
121
122 #[test]
123 async fn test_bytea_vec_u8() {
124 let mut client = new_client(get_settings()).await.unwrap();
125
126 let empty_bytes: Vec<u8> = client.read_single_value_dual_mode("select ''::bytea").await;
128 assert_eq!(empty_bytes, Vec::<u8>::new());
129
130 let test_bytes: Vec<u8> = client
131 .read_single_value_dual_mode("select '\\x48656C6C6F'::bytea")
132 .await;
133 assert_eq!(test_bytes, b"Hello".to_vec());
134
135 let binary_data: Vec<u8> = client
136 .read_single_value_dual_mode("select '\\x00010203FF'::bytea")
137 .await;
138 assert_eq!(binary_data, vec![0, 1, 2, 3, 255]);
139
140 let test_data = vec![0u8, 255u8, 42u8];
142 let round_trip_result: Vec<u8> = client
143 .read_single_value("select $1::bytea;", &[&test_data])
144 .await;
145 assert_eq!(round_trip_result, test_data);
146
147 let empty_data = Vec::<u8>::new();
148 let round_trip_empty: Vec<u8> = client
149 .read_single_value("select $1::bytea;", &[&empty_data])
150 .await;
151 assert_eq!(round_trip_empty, empty_data);
152
153 let large_data = vec![1u8; 1000];
154 let round_trip_large: Vec<u8> = client
155 .read_single_value("select $1::bytea;", &[&large_data])
156 .await;
157 assert_eq!(round_trip_large, large_data);
158
159 let param_bytes: Vec<u8> = client
161 .read_single_value(
162 "select $1::bytea;",
163 &[&vec![72u8, 101u8, 108u8, 108u8, 111u8]],
164 )
165 .await;
166 assert_eq!(param_bytes, b"Hello".to_vec());
167 }
168
169 #[test]
170 async fn test_bytea_slice() {
171 let mut client = new_client(get_settings()).await.unwrap();
172
173 let test_slice: &[u8] = b"World";
175 let received_from_slice: Vec<u8> = client
176 .read_single_value("select $1::bytea;", &[&test_slice])
177 .await;
178 assert_eq!(received_from_slice, b"World".to_vec());
179
180 }
183
184 #[test]
185 async fn test_bytea_nullable() {
186 let mut client = new_client(get_settings()).await.unwrap();
187
188 client
189 .execute_non_query_simple(
190 r#"
191 drop table if exists test_bytea_table;
192 create table test_bytea_table(data bytea);
193 insert into test_bytea_table values ('\x48656C6C6F');
194 "#,
195 )
196 .await
197 .unwrap();
198
199 let bytea_value: Option<Vec<u8>> = client
200 .read_single_value_dual_mode("select data from test_bytea_table")
201 .await;
202 assert_eq!(bytea_value, Some(b"Hello".to_vec()));
203
204 client
205 .execute_non_query("update test_bytea_table set data = null;", &[])
206 .await
207 .unwrap();
208 let null_bytea: Option<Vec<u8>> = client
209 .read_single_value_dual_mode("select data from test_bytea_table")
210 .await;
211 assert_eq!(null_bytea, None);
212
213 client
215 .execute_non_query("delete from test_bytea_table;", &[])
216 .await
217 .unwrap();
218 client
219 .execute_non_query(
220 "insert into test_bytea_table values ($1);",
221 &[&None::<Vec<u8>>],
222 )
223 .await
224 .unwrap();
225 let value: Option<Vec<u8>> = client
226 .read_single_value_dual_mode("select data from test_bytea_table")
227 .await;
228 assert_eq!(value, None);
229
230 client
232 .execute_non_query("delete from test_bytea_table;", &[])
233 .await
234 .unwrap();
235 client
236 .execute_non_query(
237 "insert into test_bytea_table values ($1);",
238 &[&Some(vec![1u8, 2u8, 3u8])],
239 )
240 .await
241 .unwrap();
242 let value: Option<Vec<u8>> = client
243 .read_single_value_dual_mode("select data from test_bytea_table")
244 .await;
245 assert_eq!(value, Some(vec![1, 2, 3]));
246
247 client
249 .execute_non_query("delete from test_bytea_table;", &[])
250 .await
251 .unwrap();
252 let slice_data: &[u8] = b"SliceTest";
253 client
254 .execute_non_query("insert into test_bytea_table values ($1);", &[&slice_data])
255 .await
256 .unwrap();
257 let value: Option<Vec<u8>> = client
258 .read_single_value_dual_mode("select data from test_bytea_table")
259 .await;
260 assert_eq!(value, Some(b"SliceTest".to_vec()));
261
262 client
264 .execute_non_query("delete from test_bytea_table;", &[])
265 .await
266 .unwrap();
267 let some_slice: Option<&[u8]> = Some(b"OptionSlice");
268 client
269 .execute_non_query("insert into test_bytea_table values ($1);", &[&some_slice])
270 .await
271 .unwrap();
272 let value: Option<Vec<u8>> = client
273 .read_single_value_dual_mode("select data from test_bytea_table")
274 .await;
275 assert_eq!(value, Some(b"OptionSlice".to_vec()));
276
277 client
279 .execute_non_query("delete from test_bytea_table;", &[])
280 .await
281 .unwrap();
282 let none_slice: Option<&[u8]> = None;
283 client
284 .execute_non_query("insert into test_bytea_table values ($1);", &[&none_slice])
285 .await
286 .unwrap();
287 let value: Option<Vec<u8>> = client
288 .read_single_value_dual_mode("select data from test_bytea_table")
289 .await;
290 assert_eq!(value, None);
291
292 }
296
297 #[test]
298 async fn test_bytea_arrays() {
299 let mut client = new_client(get_settings()).await.unwrap();
300
301 client
303 .execute_non_query_simple(
304 r#"
305 drop table if exists test_bytea_array_table;
306 create table test_bytea_array_table(data bytea[]);
307 "#,
308 )
309 .await
310 .unwrap();
311
312 client.execute_non_query("insert into test_bytea_array_table values (array['\\x48656C6C6F'::bytea, '\\x576F726C64'::bytea]);", &[]).await.unwrap();
313 let bytea_array: Vec<Vec<u8>> = client
314 .read_single_value_dual_mode("select data from test_bytea_array_table")
315 .await;
316 assert_eq!(bytea_array, vec![b"Hello".to_vec(), b"World".to_vec()]);
317
318 client
319 .execute_non_query(
320 "update test_bytea_array_table set data = array[]::bytea[]",
321 &[],
322 )
323 .await
324 .unwrap();
325 let empty_bytea_array: Vec<Vec<u8>> = client
326 .read_single_value_dual_mode("select data from test_bytea_array_table")
327 .await;
328 assert_eq!(empty_bytea_array, Vec::<Vec<u8>>::new());
329 }
330 }
331}