1use super::EncodeError;
15use bytes::BytesMut;
16
17pub struct PgEncoder;
20
21impl PgEncoder {
22 pub const FORMAT_TEXT: i16 = 0;
24 pub const FORMAT_BINARY: i16 = 1;
26
27 #[inline(always)]
28 fn result_format_wire_len(result_format: i16) -> usize {
29 if result_format == Self::FORMAT_TEXT {
30 2 } else {
32 4 }
34 }
35
36 #[inline(always)]
37 fn encode_result_formats_vec(content: &mut Vec<u8>, result_format: i16) {
38 if result_format == Self::FORMAT_TEXT {
39 content.extend_from_slice(&0i16.to_be_bytes());
40 } else {
41 content.extend_from_slice(&1i16.to_be_bytes());
42 content.extend_from_slice(&result_format.to_be_bytes());
43 }
44 }
45
46 #[inline(always)]
47 fn encode_result_formats_bytesmut(buf: &mut BytesMut, result_format: i16) {
48 if result_format == Self::FORMAT_TEXT {
49 buf.extend_from_slice(&0i16.to_be_bytes());
50 } else {
51 buf.extend_from_slice(&1i16.to_be_bytes());
52 buf.extend_from_slice(&result_format.to_be_bytes());
53 }
54 }
55
56 pub fn encode_query_string(sql: &str) -> BytesMut {
62 let mut buf = BytesMut::new();
63
64 let content_len = sql.len() + 1; if content_len > (i32::MAX as usize) - 4 {
67 return buf;
70 }
71
72 buf.extend_from_slice(b"Q");
74
75 let total_len = (content_len + 4) as i32; buf.extend_from_slice(&total_len.to_be_bytes());
79
80 buf.extend_from_slice(sql.as_bytes());
82
83 buf.extend_from_slice(&[0]);
85
86 buf
87 }
88
89 pub fn encode_terminate() -> BytesMut {
91 let mut buf = BytesMut::new();
92 buf.extend_from_slice(&[b'X', 0, 0, 0, 4]);
93 buf
94 }
95
96 pub fn encode_sync() -> BytesMut {
98 let mut buf = BytesMut::new();
99 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
100 buf
101 }
102
103 pub fn encode_parse(name: &str, sql: &str, param_types: &[u32]) -> BytesMut {
114 let mut buf = BytesMut::new();
115
116 buf.extend_from_slice(b"P");
118
119 let mut content = Vec::new();
120
121 content.extend_from_slice(name.as_bytes());
123 content.push(0);
124
125 content.extend_from_slice(sql.as_bytes());
127 content.push(0);
128
129 content.extend_from_slice(&(param_types.len() as i16).to_be_bytes());
131
132 for &oid in param_types {
134 content.extend_from_slice(&oid.to_be_bytes());
135 }
136
137 let len = (content.len() + 4) as i32;
139 buf.extend_from_slice(&len.to_be_bytes());
140 buf.extend_from_slice(&content);
141
142 buf
143 }
144
145 pub fn encode_bind(
162 portal: &str,
163 statement: &str,
164 params: &[Option<Vec<u8>>],
165 ) -> Result<BytesMut, EncodeError> {
166 Self::encode_bind_with_result_format(portal, statement, params, Self::FORMAT_TEXT)
167 }
168
169 pub fn encode_bind_with_result_format(
175 portal: &str,
176 statement: &str,
177 params: &[Option<Vec<u8>>],
178 result_format: i16,
179 ) -> Result<BytesMut, EncodeError> {
180 if params.len() > i16::MAX as usize {
181 return Err(EncodeError::TooManyParameters(params.len()));
182 }
183
184 let mut buf = BytesMut::new();
185
186 buf.extend_from_slice(b"B");
188
189 let mut content = Vec::new();
190
191 content.extend_from_slice(portal.as_bytes());
193 content.push(0);
194
195 content.extend_from_slice(statement.as_bytes());
197 content.push(0);
198
199 content.extend_from_slice(&0i16.to_be_bytes());
201
202 content.extend_from_slice(&(params.len() as i16).to_be_bytes());
204
205 for param in params {
207 match param {
208 None => {
209 content.extend_from_slice(&(-1i32).to_be_bytes());
211 }
212 Some(data) => {
213 if data.len() > i32::MAX as usize {
214 return Err(EncodeError::MessageTooLarge(data.len()));
215 }
216 content.extend_from_slice(&(data.len() as i32).to_be_bytes());
217 content.extend_from_slice(data);
218 }
219 }
220 }
221
222 Self::encode_result_formats_vec(&mut content, result_format);
224
225 let len = (content.len() + 4) as i32;
227 buf.extend_from_slice(&len.to_be_bytes());
228 buf.extend_from_slice(&content);
229
230 Ok(buf)
231 }
232
233 pub fn encode_execute(portal: &str, max_rows: i32) -> BytesMut {
240 let mut buf = BytesMut::new();
241
242 buf.extend_from_slice(b"E");
244
245 let mut content = Vec::new();
246
247 content.extend_from_slice(portal.as_bytes());
249 content.push(0);
250
251 content.extend_from_slice(&max_rows.to_be_bytes());
253
254 let len = (content.len() + 4) as i32;
256 buf.extend_from_slice(&len.to_be_bytes());
257 buf.extend_from_slice(&content);
258
259 buf
260 }
261
262 pub fn encode_describe(is_portal: bool, name: &str) -> BytesMut {
269 let mut buf = BytesMut::new();
270
271 buf.extend_from_slice(b"D");
273
274 let mut content = Vec::new();
275
276 content.push(if is_portal { b'P' } else { b'S' });
278
279 content.extend_from_slice(name.as_bytes());
281 content.push(0);
282
283 let len = (content.len() + 4) as i32;
285 buf.extend_from_slice(&len.to_be_bytes());
286 buf.extend_from_slice(&content);
287
288 buf
289 }
290
291 pub fn encode_extended_query(
295 sql: &str,
296 params: &[Option<Vec<u8>>],
297 ) -> Result<BytesMut, EncodeError> {
298 Self::encode_extended_query_with_result_format(sql, params, Self::FORMAT_TEXT)
299 }
300
301 pub fn encode_extended_query_with_result_format(
305 sql: &str,
306 params: &[Option<Vec<u8>>],
307 result_format: i16,
308 ) -> Result<BytesMut, EncodeError> {
309 if params.len() > i16::MAX as usize {
310 return Err(EncodeError::TooManyParameters(params.len()));
311 }
312
313 let params_size: usize = params
318 .iter()
319 .map(|p| 4 + p.as_ref().map_or(0, |v| v.len()))
320 .sum();
321 let result_formats_size = Self::result_format_wire_len(result_format);
322 let total_size = 9 + sql.len() + (11 + params_size + result_formats_size) + 10 + 5;
323
324 let mut buf = BytesMut::with_capacity(total_size);
325
326 buf.extend_from_slice(b"P");
328 let parse_len = (1 + sql.len() + 1 + 2 + 4) as i32; buf.extend_from_slice(&parse_len.to_be_bytes());
330 buf.extend_from_slice(&[0]); buf.extend_from_slice(sql.as_bytes());
332 buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(b"B");
337 let bind_len = (1 + 1 + 2 + 2 + params_size + result_formats_size + 4) as i32;
338 buf.extend_from_slice(&bind_len.to_be_bytes());
339 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());
343 for param in params {
344 match param {
345 None => buf.extend_from_slice(&(-1i32).to_be_bytes()),
346 Some(data) => {
347 if data.len() > i32::MAX as usize {
348 return Err(EncodeError::MessageTooLarge(data.len()));
349 }
350 buf.extend_from_slice(&(data.len() as i32).to_be_bytes());
351 buf.extend_from_slice(data);
352 }
353 }
354 }
355 Self::encode_result_formats_bytesmut(&mut buf, result_format);
356
357 buf.extend_from_slice(b"E");
359 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]);
365
366 Ok(buf)
367 }
368
369 pub fn encode_copy_fail(reason: &str) -> BytesMut {
375 let mut buf = BytesMut::new();
376 buf.extend_from_slice(b"f");
377 let content_len = reason.len() + 1; let len = (content_len + 4) as i32;
379 buf.extend_from_slice(&len.to_be_bytes());
380 buf.extend_from_slice(reason.as_bytes());
381 buf.extend_from_slice(&[0]);
382 buf
383 }
384
385 pub fn encode_close(is_portal: bool, name: &str) -> BytesMut {
392 let mut buf = BytesMut::new();
393 buf.extend_from_slice(b"C");
394 let content_len = 1 + name.len() + 1; let len = (content_len + 4) as i32;
396 buf.extend_from_slice(&len.to_be_bytes());
397 buf.extend_from_slice(&[if is_portal { b'P' } else { b'S' }]);
398 buf.extend_from_slice(name.as_bytes());
399 buf.extend_from_slice(&[0]);
400 buf
401 }
402}
403
404use bytes::BufMut;
413
414pub enum Param<'a> {
417 Null,
419 Bytes(&'a [u8]),
421}
422
423impl PgEncoder {
424 #[inline(always)]
427 fn put_i32_be(buf: &mut BytesMut, v: i32) {
428 buf.put_i32(v);
429 }
430
431 #[inline(always)]
432 fn put_i16_be(buf: &mut BytesMut, v: i16) {
433 buf.put_i16(v);
434 }
435
436 #[inline]
441 pub fn encode_bind_ultra<'a>(
442 buf: &mut BytesMut,
443 statement: &str,
444 params: &[Param<'a>],
445 ) -> Result<(), EncodeError> {
446 Self::encode_bind_ultra_with_result_format(buf, statement, params, Self::FORMAT_TEXT)
447 }
448
449 #[inline]
451 pub fn encode_bind_ultra_with_result_format<'a>(
452 buf: &mut BytesMut,
453 statement: &str,
454 params: &[Param<'a>],
455 result_format: i16,
456 ) -> Result<(), EncodeError> {
457 if params.len() > i16::MAX as usize {
458 return Err(EncodeError::TooManyParameters(params.len()));
459 }
460
461 let params_size: usize = params
463 .iter()
464 .map(|p| match p {
465 Param::Null => 4,
466 Param::Bytes(b) => 4 + b.len(),
467 })
468 .sum();
469 let result_formats_size = Self::result_format_wire_len(result_format);
470 let content_len = 1 + statement.len() + 1 + 2 + 2 + params_size + result_formats_size;
471
472 buf.reserve(1 + 4 + content_len);
474
475 buf.put_u8(b'B');
477
478 Self::put_i32_be(buf, (content_len + 4) as i32);
480
481 buf.put_u8(0);
483
484 buf.extend_from_slice(statement.as_bytes());
486 buf.put_u8(0);
487
488 Self::put_i16_be(buf, 0);
490
491 Self::put_i16_be(buf, params.len() as i16);
493
494 for param in params {
496 match param {
497 Param::Null => Self::put_i32_be(buf, -1),
498 Param::Bytes(data) => {
499 if data.len() > i32::MAX as usize {
500 return Err(EncodeError::MessageTooLarge(data.len()));
501 }
502 Self::put_i32_be(buf, data.len() as i32);
503 buf.extend_from_slice(data);
504 }
505 }
506 }
507
508 Self::encode_result_formats_bytesmut(buf, result_format);
510 Ok(())
511 }
512
513 #[inline(always)]
515 pub fn encode_execute_ultra(buf: &mut BytesMut) {
516 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
519 }
520
521 #[inline(always)]
523 pub fn encode_sync_ultra(buf: &mut BytesMut) {
524 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
525 }
526
527 #[inline]
532 pub fn encode_bind_to(
533 buf: &mut BytesMut,
534 statement: &str,
535 params: &[Option<Vec<u8>>],
536 ) -> Result<(), EncodeError> {
537 Self::encode_bind_to_with_result_format(buf, statement, params, Self::FORMAT_TEXT)
538 }
539
540 #[inline]
542 pub fn encode_bind_to_with_result_format(
543 buf: &mut BytesMut,
544 statement: &str,
545 params: &[Option<Vec<u8>>],
546 result_format: i16,
547 ) -> Result<(), EncodeError> {
548 if params.len() > i16::MAX as usize {
549 return Err(EncodeError::TooManyParameters(params.len()));
550 }
551
552 let params_size: usize = params
556 .iter()
557 .map(|p| 4 + p.as_ref().map_or(0, |v| v.len()))
558 .sum();
559 let result_formats_size = Self::result_format_wire_len(result_format);
560 let content_len = 1 + statement.len() + 1 + 2 + 2 + params_size + result_formats_size;
561
562 buf.reserve(1 + 4 + content_len);
563
564 buf.put_u8(b'B');
566
567 Self::put_i32_be(buf, (content_len + 4) as i32);
569
570 buf.put_u8(0);
572
573 buf.extend_from_slice(statement.as_bytes());
575 buf.put_u8(0);
576
577 Self::put_i16_be(buf, 0);
579
580 Self::put_i16_be(buf, params.len() as i16);
582
583 for param in params {
585 match param {
586 None => Self::put_i32_be(buf, -1),
587 Some(data) => {
588 if data.len() > i32::MAX as usize {
589 return Err(EncodeError::MessageTooLarge(data.len()));
590 }
591 Self::put_i32_be(buf, data.len() as i32);
592 buf.extend_from_slice(data);
593 }
594 }
595 }
596
597 Self::encode_result_formats_bytesmut(buf, result_format);
599 Ok(())
600 }
601
602 #[inline]
604 pub fn encode_execute_to(buf: &mut BytesMut) {
605 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
607 }
608
609 #[inline]
611 pub fn encode_sync_to(buf: &mut BytesMut) {
612 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
613 }
614}
615
616#[cfg(test)]
617mod tests {
618 use super::*;
619
620 #[test]
622 fn test_encode_query_string() {
623 let sql = "SELECT 1";
624 let bytes = PgEncoder::encode_query_string(sql);
625
626 assert_eq!(bytes[0], b'Q');
628
629 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
631 assert_eq!(len, 13);
632
633 assert_eq!(&bytes[5..13], b"SELECT 1");
635
636 assert_eq!(bytes[13], 0);
638 }
639
640 #[test]
641 fn test_encode_terminate() {
642 let bytes = PgEncoder::encode_terminate();
643 assert_eq!(bytes.as_ref(), &[b'X', 0, 0, 0, 4]);
644 }
645
646 #[test]
647 fn test_encode_sync() {
648 let bytes = PgEncoder::encode_sync();
649 assert_eq!(bytes.as_ref(), &[b'S', 0, 0, 0, 4]);
650 }
651
652 #[test]
653 fn test_encode_parse() {
654 let bytes = PgEncoder::encode_parse("", "SELECT $1", &[]);
655
656 assert_eq!(bytes[0], b'P');
658
659 let content = String::from_utf8_lossy(&bytes[5..]);
661 assert!(content.contains("SELECT $1"));
662 }
663
664 #[test]
665 fn test_encode_bind() {
666 let params = vec![
667 Some(b"42".to_vec()),
668 None, ];
670 let bytes = PgEncoder::encode_bind("", "", ¶ms).unwrap();
671
672 assert_eq!(bytes[0], b'B');
674
675 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
677 assert!(len > 4); }
679
680 #[test]
681 fn test_encode_bind_binary_result_format() {
682 let bytes =
683 PgEncoder::encode_bind_with_result_format("", "", &[], PgEncoder::FORMAT_BINARY)
684 .unwrap();
685
686 assert_eq!(&bytes[11..15], &[0, 1, 0, 1]);
689 }
690
691 #[test]
692 fn test_encode_execute() {
693 let bytes = PgEncoder::encode_execute("", 0);
694
695 assert_eq!(bytes[0], b'E');
697
698 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
700 assert_eq!(len, 9);
701 }
702
703 #[test]
704 fn test_encode_extended_query() {
705 let params = vec![Some(b"hello".to_vec())];
706 let bytes = PgEncoder::encode_extended_query("SELECT $1", ¶ms).unwrap();
707
708 assert!(bytes.windows(1).any(|w| w == [b'P']));
710 assert!(bytes.windows(1).any(|w| w == [b'B']));
711 assert!(bytes.windows(1).any(|w| w == [b'E']));
712 assert!(bytes.windows(1).any(|w| w == [b'S']));
713 }
714
715 #[test]
716 fn test_encode_extended_query_binary_result_format() {
717 let bytes = PgEncoder::encode_extended_query_with_result_format(
718 "SELECT 1",
719 &[],
720 PgEncoder::FORMAT_BINARY,
721 )
722 .unwrap();
723
724 let parse_len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]) as usize;
725 let bind_start = 1 + parse_len;
726 assert_eq!(bytes[bind_start], b'B');
727
728 let bind_len = i32::from_be_bytes([
729 bytes[bind_start + 1],
730 bytes[bind_start + 2],
731 bytes[bind_start + 3],
732 bytes[bind_start + 4],
733 ]);
734 assert_eq!(bind_len, 14);
735
736 let bind_content = &bytes[bind_start + 5..bind_start + 1 + bind_len as usize];
737 assert_eq!(&bind_content[6..10], &[0, 1, 0, 1]);
738 }
739
740 #[test]
741 fn test_encode_copy_fail() {
742 let bytes = PgEncoder::encode_copy_fail("bad data");
743 assert_eq!(bytes[0], b'f');
744 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
745 assert_eq!(len as usize, 4 + "bad data".len() + 1);
746 assert_eq!(&bytes[5..13], b"bad data");
747 assert_eq!(bytes[13], 0);
748 }
749
750 #[test]
751 fn test_encode_close_statement() {
752 let bytes = PgEncoder::encode_close(false, "my_stmt");
753 assert_eq!(bytes[0], b'C');
754 assert_eq!(bytes[5], b'S'); assert_eq!(&bytes[6..13], b"my_stmt");
756 assert_eq!(bytes[13], 0);
757 }
758
759 #[test]
760 fn test_encode_close_portal() {
761 let bytes = PgEncoder::encode_close(true, "");
762 assert_eq!(bytes[0], b'C');
763 assert_eq!(bytes[5], b'P'); assert_eq!(bytes[6], 0); }
766
767 #[test]
768 fn test_encode_bind_to_binary_result_format() {
769 let mut buf = BytesMut::new();
770 PgEncoder::encode_bind_to_with_result_format(&mut buf, "", &[], PgEncoder::FORMAT_BINARY)
771 .unwrap();
772
773 assert_eq!(&buf[11..15], &[0, 1, 0, 1]);
774 }
775
776 #[test]
777 fn test_encode_bind_ultra_binary_result_format() {
778 let mut buf = BytesMut::new();
779 PgEncoder::encode_bind_ultra_with_result_format(
780 &mut buf,
781 "",
782 &[],
783 PgEncoder::FORMAT_BINARY,
784 )
785 .unwrap();
786
787 assert_eq!(&buf[11..15], &[0, 1, 0, 1]);
788 }
789}