1use bytes::BytesMut;
15use super::EncodeError;
16
17pub struct PgEncoder;
20
21impl PgEncoder {
22 pub fn encode_query_string(sql: &str) -> BytesMut {
28 let mut buf = BytesMut::new();
29
30 buf.extend_from_slice(b"Q");
32
33 let content_len = sql.len() + 1; let total_len = (content_len + 4) as i32; buf.extend_from_slice(&total_len.to_be_bytes());
39
40 buf.extend_from_slice(sql.as_bytes());
42
43 buf.extend_from_slice(&[0]);
45
46 buf
47 }
48
49 pub fn encode_terminate() -> BytesMut {
51 let mut buf = BytesMut::new();
52 buf.extend_from_slice(&[b'X', 0, 0, 0, 4]);
53 buf
54 }
55
56 pub fn encode_sync() -> BytesMut {
58 let mut buf = BytesMut::new();
59 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
60 buf
61 }
62
63 pub fn encode_parse(name: &str, sql: &str, param_types: &[u32]) -> BytesMut {
74 let mut buf = BytesMut::new();
75
76 buf.extend_from_slice(b"P");
78
79 let mut content = Vec::new();
80
81 content.extend_from_slice(name.as_bytes());
83 content.push(0);
84
85 content.extend_from_slice(sql.as_bytes());
87 content.push(0);
88
89 content.extend_from_slice(&(param_types.len() as i16).to_be_bytes());
91
92 for &oid in param_types {
94 content.extend_from_slice(&oid.to_be_bytes());
95 }
96
97 let len = (content.len() + 4) as i32;
99 buf.extend_from_slice(&len.to_be_bytes());
100 buf.extend_from_slice(&content);
101
102 buf
103 }
104
105 pub fn encode_bind(portal: &str, statement: &str, params: &[Option<Vec<u8>>]) -> Result<BytesMut, EncodeError> {
116 if params.len() > i16::MAX as usize {
117 return Err(EncodeError::TooManyParameters(params.len()));
118 }
119
120 let mut buf = BytesMut::new();
121
122 buf.extend_from_slice(b"B");
124
125 let mut content = Vec::new();
126
127 content.extend_from_slice(portal.as_bytes());
129 content.push(0);
130
131 content.extend_from_slice(statement.as_bytes());
133 content.push(0);
134
135 content.extend_from_slice(&0i16.to_be_bytes());
137
138 content.extend_from_slice(&(params.len() as i16).to_be_bytes());
140
141 for param in params {
143 match param {
144 None => {
145 content.extend_from_slice(&(-1i32).to_be_bytes());
147 }
148 Some(data) => {
149 content.extend_from_slice(&(data.len() as i32).to_be_bytes());
150 content.extend_from_slice(data);
151 }
152 }
153 }
154
155 content.extend_from_slice(&0i16.to_be_bytes());
157
158 let len = (content.len() + 4) as i32;
160 buf.extend_from_slice(&len.to_be_bytes());
161 buf.extend_from_slice(&content);
162
163 Ok(buf)
164 }
165
166 pub fn encode_execute(portal: &str, max_rows: i32) -> BytesMut {
173 let mut buf = BytesMut::new();
174
175 buf.extend_from_slice(b"E");
177
178 let mut content = Vec::new();
179
180 content.extend_from_slice(portal.as_bytes());
182 content.push(0);
183
184 content.extend_from_slice(&max_rows.to_be_bytes());
186
187 let len = (content.len() + 4) as i32;
189 buf.extend_from_slice(&len.to_be_bytes());
190 buf.extend_from_slice(&content);
191
192 buf
193 }
194
195 pub fn encode_describe(is_portal: bool, name: &str) -> BytesMut {
202 let mut buf = BytesMut::new();
203
204 buf.extend_from_slice(b"D");
206
207 let mut content = Vec::new();
208
209 content.push(if is_portal { b'P' } else { b'S' });
211
212 content.extend_from_slice(name.as_bytes());
214 content.push(0);
215
216 let len = (content.len() + 4) as i32;
218 buf.extend_from_slice(&len.to_be_bytes());
219 buf.extend_from_slice(&content);
220
221 buf
222 }
223
224 pub fn encode_extended_query(sql: &str, params: &[Option<Vec<u8>>]) -> Result<BytesMut, EncodeError> {
228 if params.len() > i16::MAX as usize {
229 return Err(EncodeError::TooManyParameters(params.len()));
230 }
231
232 let params_size: usize = params
237 .iter()
238 .map(|p| 4 + p.as_ref().map_or(0, |v| v.len()))
239 .sum();
240 let total_size = 9 + sql.len() + 13 + params_size + 10 + 5;
241
242 let mut buf = BytesMut::with_capacity(total_size);
243
244 buf.extend_from_slice(b"P");
246 let parse_len = (1 + sql.len() + 1 + 2 + 4) as i32; buf.extend_from_slice(&parse_len.to_be_bytes());
248 buf.extend_from_slice(&[0]); buf.extend_from_slice(sql.as_bytes());
250 buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(b"B");
255 let bind_len = (1 + 1 + 2 + 2 + params_size + 2 + 4) as i32;
256 buf.extend_from_slice(&bind_len.to_be_bytes());
257 buf.extend_from_slice(&[0]); buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(&(params.len() as i16).to_be_bytes());
261 for param in params {
262 match param {
263 None => buf.extend_from_slice(&(-1i32).to_be_bytes()),
264 Some(data) => {
265 buf.extend_from_slice(&(data.len() as i32).to_be_bytes());
266 buf.extend_from_slice(data);
267 }
268 }
269 }
270 buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(b"E");
274 buf.extend_from_slice(&9i32.to_be_bytes()); buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i32.to_be_bytes()); buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
280
281 Ok(buf)
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
291 fn test_encode_query_string() {
292 let sql = "SELECT 1";
293 let bytes = PgEncoder::encode_query_string(sql);
294
295 assert_eq!(bytes[0], b'Q');
297
298 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
300 assert_eq!(len, 13);
301
302 assert_eq!(&bytes[5..13], b"SELECT 1");
304
305 assert_eq!(bytes[13], 0);
307 }
308
309 #[test]
310 fn test_encode_terminate() {
311 let bytes = PgEncoder::encode_terminate();
312 assert_eq!(bytes.as_ref(), &[b'X', 0, 0, 0, 4]);
313 }
314
315 #[test]
316 fn test_encode_sync() {
317 let bytes = PgEncoder::encode_sync();
318 assert_eq!(bytes.as_ref(), &[b'S', 0, 0, 0, 4]);
319 }
320
321 #[test]
322 fn test_encode_parse() {
323 let bytes = PgEncoder::encode_parse("", "SELECT $1", &[]);
324
325 assert_eq!(bytes[0], b'P');
327
328 let content = String::from_utf8_lossy(&bytes[5..]);
330 assert!(content.contains("SELECT $1"));
331 }
332
333 #[test]
334 fn test_encode_bind() {
335 let params = vec![
336 Some(b"42".to_vec()),
337 None, ];
339 let bytes = PgEncoder::encode_bind("", "", ¶ms).unwrap();
340
341 assert_eq!(bytes[0], b'B');
343
344 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
346 assert!(len > 4); }
348
349 #[test]
350 fn test_encode_execute() {
351 let bytes = PgEncoder::encode_execute("", 0);
352
353 assert_eq!(bytes[0], b'E');
355
356 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
358 assert_eq!(len, 9);
359 }
360
361 #[test]
362 fn test_encode_extended_query() {
363 let params = vec![Some(b"hello".to_vec())];
364 let bytes = PgEncoder::encode_extended_query("SELECT $1", ¶ms).unwrap();
365
366 assert!(bytes.windows(1).any(|w| w == [b'P']));
368 assert!(bytes.windows(1).any(|w| w == [b'B']));
369 assert!(bytes.windows(1).any(|w| w == [b'E']));
370 assert!(bytes.windows(1).any(|w| w == [b'S']));
371 }
372}
373
374use bytes::BufMut;
383
384pub enum Param<'a> {
387 Null,
388 Bytes(&'a [u8]),
389}
390
391impl PgEncoder {
392 #[inline(always)]
395 fn put_i32_be(buf: &mut BytesMut, v: i32) {
396 buf.put_i32(v);
397 }
398
399 #[inline(always)]
400 fn put_i16_be(buf: &mut BytesMut, v: i16) {
401 buf.put_i16(v);
402 }
403
404 #[inline]
409 pub fn encode_bind_ultra<'a>(buf: &mut BytesMut, statement: &str, params: &[Param<'a>]) -> Result<(), EncodeError> {
410 if params.len() > i16::MAX as usize {
411 return Err(EncodeError::TooManyParameters(params.len()));
412 }
413
414 let params_size: usize = params
416 .iter()
417 .map(|p| match p {
418 Param::Null => 4,
419 Param::Bytes(b) => 4 + b.len(),
420 })
421 .sum();
422 let content_len = 1 + statement.len() + 1 + 2 + 2 + params_size + 2;
423
424 buf.reserve(1 + 4 + content_len);
426
427 buf.put_u8(b'B');
429
430 Self::put_i32_be(buf, (content_len + 4) as i32);
432
433 buf.put_u8(0);
435
436 buf.extend_from_slice(statement.as_bytes());
438 buf.put_u8(0);
439
440 Self::put_i16_be(buf, 0);
442
443 Self::put_i16_be(buf, params.len() as i16);
445
446 for param in params {
448 match param {
449 Param::Null => Self::put_i32_be(buf, -1),
450 Param::Bytes(data) => {
451 Self::put_i32_be(buf, data.len() as i32);
452 buf.extend_from_slice(data);
453 }
454 }
455 }
456
457 Self::put_i16_be(buf, 0);
459 Ok(())
460 }
461
462 #[inline(always)]
464 pub fn encode_execute_ultra(buf: &mut BytesMut) {
465 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
468 }
469
470 #[inline(always)]
472 pub fn encode_sync_ultra(buf: &mut BytesMut) {
473 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
474 }
475
476 #[inline]
481 pub fn encode_bind_to(buf: &mut BytesMut, statement: &str, params: &[Option<Vec<u8>>]) -> Result<(), EncodeError> {
482 if params.len() > i16::MAX as usize {
483 return Err(EncodeError::TooManyParameters(params.len()));
484 }
485
486 let params_size: usize = params
489 .iter()
490 .map(|p| 4 + p.as_ref().map_or(0, |v| v.len()))
491 .sum();
492 let content_len = 1 + statement.len() + 1 + 2 + 2 + params_size + 2;
493
494 buf.reserve(1 + 4 + content_len);
495
496 buf.put_u8(b'B');
498
499 Self::put_i32_be(buf, (content_len + 4) as i32);
501
502 buf.put_u8(0);
504
505 buf.extend_from_slice(statement.as_bytes());
507 buf.put_u8(0);
508
509 Self::put_i16_be(buf, 0);
511
512 Self::put_i16_be(buf, params.len() as i16);
514
515 for param in params {
517 match param {
518 None => Self::put_i32_be(buf, -1),
519 Some(data) => {
520 Self::put_i32_be(buf, data.len() as i32);
521 buf.extend_from_slice(data);
522 }
523 }
524 }
525
526 Self::put_i16_be(buf, 0);
528 Ok(())
529 }
530
531 #[inline]
533 pub fn encode_execute_to(buf: &mut BytesMut) {
534 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
536 }
537
538 #[inline]
540 pub fn encode_sync_to(buf: &mut BytesMut) {
541 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
542 }
543}