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 param_format_wire_len(param_format: i16) -> usize {
29 if param_format == Self::FORMAT_TEXT {
30 2 } else {
32 4 }
34 }
35
36 #[inline(always)]
37 fn encode_param_formats_vec(content: &mut Vec<u8>, param_format: i16) {
38 if param_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(¶m_format.to_be_bytes());
43 }
44 }
45
46 #[inline(always)]
47 fn encode_param_formats_bytesmut(buf: &mut BytesMut, param_format: i16) {
48 if param_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(¶m_format.to_be_bytes());
53 }
54 }
55
56 #[inline(always)]
57 fn result_format_wire_len(result_format: i16) -> usize {
58 if result_format == Self::FORMAT_TEXT {
59 2 } else {
61 4 }
63 }
64
65 #[inline(always)]
66 fn encode_result_formats_vec(content: &mut Vec<u8>, result_format: i16) {
67 if result_format == Self::FORMAT_TEXT {
68 content.extend_from_slice(&0i16.to_be_bytes());
69 } else {
70 content.extend_from_slice(&1i16.to_be_bytes());
71 content.extend_from_slice(&result_format.to_be_bytes());
72 }
73 }
74
75 #[inline(always)]
76 fn encode_result_formats_bytesmut(buf: &mut BytesMut, result_format: i16) {
77 if result_format == Self::FORMAT_TEXT {
78 buf.extend_from_slice(&0i16.to_be_bytes());
79 } else {
80 buf.extend_from_slice(&1i16.to_be_bytes());
81 buf.extend_from_slice(&result_format.to_be_bytes());
82 }
83 }
84
85 #[inline(always)]
86 fn content_len_to_wire_len(content_len: usize) -> Result<i32, EncodeError> {
87 let total = content_len
88 .checked_add(4)
89 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
90 i32::try_from(total).map_err(|_| EncodeError::MessageTooLarge(total))
91 }
92
93 #[inline(always)]
94 fn usize_to_i16(n: usize) -> Result<i16, EncodeError> {
95 i16::try_from(n).map_err(|_| EncodeError::TooManyParameters(n))
96 }
97
98 #[inline(always)]
99 fn usize_to_i32(n: usize) -> Result<i32, EncodeError> {
100 i32::try_from(n).map_err(|_| EncodeError::MessageTooLarge(n))
101 }
102
103 #[inline(always)]
104 fn has_nul(s: &str) -> bool {
105 s.as_bytes().contains(&0)
106 }
107
108 pub fn try_encode_query_string(sql: &str) -> Result<BytesMut, EncodeError> {
110 if Self::has_nul(sql) {
111 return Err(EncodeError::NullByte);
112 }
113
114 let mut buf = BytesMut::new();
115 let content_len = sql.len() + 1; let total_len = Self::content_len_to_wire_len(content_len)?;
117
118 buf.extend_from_slice(b"Q");
119 buf.extend_from_slice(&total_len.to_be_bytes());
120 buf.extend_from_slice(sql.as_bytes());
121 buf.extend_from_slice(&[0]);
122 Ok(buf)
123 }
124
125 pub fn encode_terminate() -> BytesMut {
127 let mut buf = BytesMut::new();
128 buf.extend_from_slice(&[b'X', 0, 0, 0, 4]);
129 buf
130 }
131
132 pub fn encode_sync() -> BytesMut {
134 let mut buf = BytesMut::new();
135 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
136 buf
137 }
138
139 pub fn try_encode_parse(
143 name: &str,
144 sql: &str,
145 param_types: &[u32],
146 ) -> Result<BytesMut, EncodeError> {
147 if Self::has_nul(name) || Self::has_nul(sql) {
148 return Err(EncodeError::NullByte);
149 }
150 if param_types.len() > i16::MAX as usize {
151 return Err(EncodeError::TooManyParameters(param_types.len()));
152 }
153
154 let mut buf = BytesMut::new();
155 buf.extend_from_slice(b"P");
156
157 let mut content = Vec::new();
158 content.extend_from_slice(name.as_bytes());
159 content.push(0);
160 content.extend_from_slice(sql.as_bytes());
161 content.push(0);
162 let param_count = Self::usize_to_i16(param_types.len())?;
163 content.extend_from_slice(¶m_count.to_be_bytes());
164 for &oid in param_types {
165 content.extend_from_slice(&oid.to_be_bytes());
166 }
167
168 let len = Self::content_len_to_wire_len(content.len())?;
169 buf.extend_from_slice(&len.to_be_bytes());
170 buf.extend_from_slice(&content);
171 Ok(buf)
172 }
173
174 pub fn encode_bind(
191 portal: &str,
192 statement: &str,
193 params: &[Option<Vec<u8>>],
194 ) -> Result<BytesMut, EncodeError> {
195 Self::encode_bind_with_result_format(portal, statement, params, Self::FORMAT_TEXT)
196 }
197
198 pub fn encode_bind_with_result_format(
204 portal: &str,
205 statement: &str,
206 params: &[Option<Vec<u8>>],
207 result_format: i16,
208 ) -> Result<BytesMut, EncodeError> {
209 Self::encode_bind_with_formats(portal, statement, params, Self::FORMAT_TEXT, result_format)
210 }
211
212 pub fn encode_bind_with_formats(
221 portal: &str,
222 statement: &str,
223 params: &[Option<Vec<u8>>],
224 param_format: i16,
225 result_format: i16,
226 ) -> Result<BytesMut, EncodeError> {
227 if Self::has_nul(portal) || Self::has_nul(statement) {
228 return Err(EncodeError::NullByte);
229 }
230 if params.len() > i16::MAX as usize {
231 return Err(EncodeError::TooManyParameters(params.len()));
232 }
233
234 let mut buf = BytesMut::new();
235
236 buf.extend_from_slice(b"B");
238
239 let mut content = Vec::new();
240
241 content.extend_from_slice(portal.as_bytes());
243 content.push(0);
244
245 content.extend_from_slice(statement.as_bytes());
247 content.push(0);
248
249 Self::encode_param_formats_vec(&mut content, param_format);
251
252 let param_count = Self::usize_to_i16(params.len())?;
254 content.extend_from_slice(¶m_count.to_be_bytes());
255
256 for param in params {
258 match param {
259 None => {
260 content.extend_from_slice(&(-1i32).to_be_bytes());
262 }
263 Some(data) => {
264 let data_len = Self::usize_to_i32(data.len())?;
265 content.extend_from_slice(&data_len.to_be_bytes());
266 content.extend_from_slice(data);
267 }
268 }
269 }
270
271 Self::encode_result_formats_vec(&mut content, result_format);
273
274 let len = Self::content_len_to_wire_len(content.len())?;
276 buf.extend_from_slice(&len.to_be_bytes());
277 buf.extend_from_slice(&content);
278
279 Ok(buf)
280 }
281
282 pub fn try_encode_execute(portal: &str, max_rows: i32) -> Result<BytesMut, EncodeError> {
284 if Self::has_nul(portal) {
285 return Err(EncodeError::NullByte);
286 }
287 if max_rows < 0 {
288 return Err(EncodeError::InvalidMaxRows(max_rows));
289 }
290
291 let mut buf = BytesMut::new();
292 buf.extend_from_slice(b"E");
293
294 let mut content = Vec::new();
295 content.extend_from_slice(portal.as_bytes());
296 content.push(0);
297 content.extend_from_slice(&max_rows.to_be_bytes());
298
299 let len = Self::content_len_to_wire_len(content.len())?;
300 buf.extend_from_slice(&len.to_be_bytes());
301 buf.extend_from_slice(&content);
302 Ok(buf)
303 }
304
305 pub fn try_encode_describe(is_portal: bool, name: &str) -> Result<BytesMut, EncodeError> {
307 if Self::has_nul(name) {
308 return Err(EncodeError::NullByte);
309 }
310
311 let mut buf = BytesMut::new();
312 buf.extend_from_slice(b"D");
313
314 let mut content = Vec::new();
315 content.push(if is_portal { b'P' } else { b'S' });
316 content.extend_from_slice(name.as_bytes());
317 content.push(0);
318
319 let len = Self::content_len_to_wire_len(content.len())?;
320 buf.extend_from_slice(&len.to_be_bytes());
321 buf.extend_from_slice(&content);
322 Ok(buf)
323 }
324
325 pub fn encode_extended_query(
329 sql: &str,
330 params: &[Option<Vec<u8>>],
331 ) -> Result<BytesMut, EncodeError> {
332 Self::encode_extended_query_with_result_format(sql, params, Self::FORMAT_TEXT)
333 }
334
335 pub fn encode_extended_query_with_result_format(
339 sql: &str,
340 params: &[Option<Vec<u8>>],
341 result_format: i16,
342 ) -> Result<BytesMut, EncodeError> {
343 Self::encode_extended_query_with_formats(sql, params, Self::FORMAT_TEXT, result_format)
344 }
345
346 pub fn encode_extended_query_with_formats(
351 sql: &str,
352 params: &[Option<Vec<u8>>],
353 param_format: i16,
354 result_format: i16,
355 ) -> Result<BytesMut, EncodeError> {
356 if Self::has_nul(sql) {
357 return Err(EncodeError::NullByte);
358 }
359 if params.len() > i16::MAX as usize {
360 return Err(EncodeError::TooManyParameters(params.len()));
361 }
362
363 let params_size = params.iter().try_fold(0usize, |acc, p| {
368 let field_size = 4usize
369 .checked_add(p.as_ref().map_or(0usize, |v| v.len()))
370 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
371 acc.checked_add(field_size)
372 .ok_or(EncodeError::MessageTooLarge(usize::MAX))
373 })?;
374 let param_formats_size = Self::param_format_wire_len(param_format);
375 let result_formats_size = Self::result_format_wire_len(result_format);
376 let total_size = 9usize
377 .checked_add(sql.len())
378 .and_then(|v| v.checked_add(9))
379 .and_then(|v| v.checked_add(params_size))
380 .and_then(|v| v.checked_add(param_formats_size))
381 .and_then(|v| v.checked_add(result_formats_size))
382 .and_then(|v| v.checked_add(10))
383 .and_then(|v| v.checked_add(5))
384 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
385
386 let mut buf = BytesMut::with_capacity(total_size);
387
388 buf.extend_from_slice(b"P");
390 let parse_content_len = 1usize
391 .checked_add(sql.len())
392 .and_then(|v| v.checked_add(1))
393 .and_then(|v| v.checked_add(2))
394 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
395 let parse_len = Self::content_len_to_wire_len(parse_content_len)?;
396 buf.extend_from_slice(&parse_len.to_be_bytes());
397 buf.extend_from_slice(&[0]); buf.extend_from_slice(sql.as_bytes());
399 buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(b"B");
404 let bind_content_len = 1usize
405 .checked_add(1)
406 .and_then(|v| v.checked_add(2))
407 .and_then(|v| v.checked_add(param_formats_size))
408 .and_then(|v| v.checked_add(params_size))
409 .and_then(|v| v.checked_add(result_formats_size))
410 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
411 let bind_len = Self::content_len_to_wire_len(bind_content_len)?;
412 buf.extend_from_slice(&bind_len.to_be_bytes());
413 buf.extend_from_slice(&[0]); buf.extend_from_slice(&[0]); Self::encode_param_formats_bytesmut(&mut buf, param_format);
416 let param_count = Self::usize_to_i16(params.len())?;
417 buf.extend_from_slice(¶m_count.to_be_bytes());
418 for param in params {
419 match param {
420 None => buf.extend_from_slice(&(-1i32).to_be_bytes()),
421 Some(data) => {
422 let data_len = Self::usize_to_i32(data.len())?;
423 buf.extend_from_slice(&data_len.to_be_bytes());
424 buf.extend_from_slice(data);
425 }
426 }
427 }
428 Self::encode_result_formats_bytesmut(&mut buf, result_format);
429
430 buf.extend_from_slice(b"E");
432 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]);
438
439 Ok(buf)
440 }
441
442 pub fn try_encode_copy_fail(reason: &str) -> Result<BytesMut, EncodeError> {
444 if Self::has_nul(reason) {
445 return Err(EncodeError::NullByte);
446 }
447
448 let mut buf = BytesMut::new();
449 buf.extend_from_slice(b"f");
450 let content_len = reason.len() + 1; let len = Self::content_len_to_wire_len(content_len)?;
452 buf.extend_from_slice(&len.to_be_bytes());
453 buf.extend_from_slice(reason.as_bytes());
454 buf.extend_from_slice(&[0]);
455 Ok(buf)
456 }
457
458 pub fn try_encode_close(is_portal: bool, name: &str) -> Result<BytesMut, EncodeError> {
460 if Self::has_nul(name) {
461 return Err(EncodeError::NullByte);
462 }
463
464 let mut buf = BytesMut::new();
465 buf.extend_from_slice(b"C");
466 let content_len = 1 + name.len() + 1; let len = Self::content_len_to_wire_len(content_len)?;
468 buf.extend_from_slice(&len.to_be_bytes());
469 buf.extend_from_slice(&[if is_portal { b'P' } else { b'S' }]);
470 buf.extend_from_slice(name.as_bytes());
471 buf.extend_from_slice(&[0]);
472 Ok(buf)
473 }
474}
475
476use bytes::BufMut;
485
486pub enum Param<'a> {
489 Null,
491 Bytes(&'a [u8]),
493}
494
495impl PgEncoder {
496 #[inline(always)]
499 fn put_i32_be(buf: &mut BytesMut, v: i32) {
500 buf.put_i32(v);
501 }
502
503 #[inline(always)]
504 fn put_i16_be(buf: &mut BytesMut, v: i16) {
505 buf.put_i16(v);
506 }
507
508 #[inline]
513 pub fn encode_bind_ultra<'a>(
514 buf: &mut BytesMut,
515 statement: &str,
516 params: &[Param<'a>],
517 ) -> Result<(), EncodeError> {
518 Self::encode_bind_ultra_with_result_format(buf, statement, params, Self::FORMAT_TEXT)
519 }
520
521 #[inline]
523 pub fn encode_bind_ultra_with_result_format<'a>(
524 buf: &mut BytesMut,
525 statement: &str,
526 params: &[Param<'a>],
527 result_format: i16,
528 ) -> Result<(), EncodeError> {
529 Self::encode_bind_ultra_with_formats(
530 buf,
531 statement,
532 params,
533 Self::FORMAT_TEXT,
534 result_format,
535 )
536 }
537
538 #[inline]
540 pub fn encode_bind_ultra_with_formats<'a>(
541 buf: &mut BytesMut,
542 statement: &str,
543 params: &[Param<'a>],
544 param_format: i16,
545 result_format: i16,
546 ) -> Result<(), EncodeError> {
547 if Self::has_nul(statement) {
548 return Err(EncodeError::NullByte);
549 }
550 if params.len() > i16::MAX as usize {
551 return Err(EncodeError::TooManyParameters(params.len()));
552 }
553
554 let params_size = params.iter().try_fold(0usize, |acc, p| {
556 let field_size = match p {
557 Param::Null => 4usize,
558 Param::Bytes(b) => 4usize
559 .checked_add(b.len())
560 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?,
561 };
562 acc.checked_add(field_size)
563 .ok_or(EncodeError::MessageTooLarge(usize::MAX))
564 })?;
565 let param_formats_size = Self::param_format_wire_len(param_format);
566 let result_formats_size = Self::result_format_wire_len(result_format);
567 let content_len = 1usize
568 .checked_add(statement.len())
569 .and_then(|v| v.checked_add(1))
570 .and_then(|v| v.checked_add(2))
571 .and_then(|v| v.checked_add(param_formats_size))
572 .and_then(|v| v.checked_add(params_size))
573 .and_then(|v| v.checked_add(result_formats_size))
574 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
575 let wire_len = Self::content_len_to_wire_len(content_len)?;
576
577 buf.reserve(1 + 4 + content_len);
579
580 buf.put_u8(b'B');
582
583 Self::put_i32_be(buf, wire_len);
585
586 buf.put_u8(0);
588
589 buf.extend_from_slice(statement.as_bytes());
591 buf.put_u8(0);
592
593 Self::encode_param_formats_bytesmut(buf, param_format);
595
596 let param_count = Self::usize_to_i16(params.len())?;
598 Self::put_i16_be(buf, param_count);
599
600 for param in params {
602 match param {
603 Param::Null => Self::put_i32_be(buf, -1),
604 Param::Bytes(data) => {
605 let data_len = Self::usize_to_i32(data.len())?;
606 Self::put_i32_be(buf, data_len);
607 buf.extend_from_slice(data);
608 }
609 }
610 }
611
612 Self::encode_result_formats_bytesmut(buf, result_format);
614 Ok(())
615 }
616
617 #[inline(always)]
619 pub fn encode_execute_ultra(buf: &mut BytesMut) {
620 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
623 }
624
625 #[inline(always)]
627 pub fn encode_sync_ultra(buf: &mut BytesMut) {
628 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
629 }
630
631 #[inline]
636 pub fn encode_bind_to(
637 buf: &mut BytesMut,
638 statement: &str,
639 params: &[Option<Vec<u8>>],
640 ) -> Result<(), EncodeError> {
641 Self::encode_bind_to_with_result_format(buf, statement, params, Self::FORMAT_TEXT)
642 }
643
644 #[inline]
646 pub fn encode_bind_to_with_result_format(
647 buf: &mut BytesMut,
648 statement: &str,
649 params: &[Option<Vec<u8>>],
650 result_format: i16,
651 ) -> Result<(), EncodeError> {
652 Self::encode_bind_to_with_formats(buf, statement, params, Self::FORMAT_TEXT, result_format)
653 }
654
655 #[inline]
657 pub fn encode_bind_to_with_formats(
658 buf: &mut BytesMut,
659 statement: &str,
660 params: &[Option<Vec<u8>>],
661 param_format: i16,
662 result_format: i16,
663 ) -> Result<(), EncodeError> {
664 if Self::has_nul(statement) {
665 return Err(EncodeError::NullByte);
666 }
667 if params.len() > i16::MAX as usize {
668 return Err(EncodeError::TooManyParameters(params.len()));
669 }
670
671 let params_size = params.iter().try_fold(0usize, |acc, p| {
675 let field_size = 4usize
676 .checked_add(p.as_ref().map_or(0usize, |v| v.len()))
677 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
678 acc.checked_add(field_size)
679 .ok_or(EncodeError::MessageTooLarge(usize::MAX))
680 })?;
681 let param_formats_size = Self::param_format_wire_len(param_format);
682 let result_formats_size = Self::result_format_wire_len(result_format);
683 let content_len = 1usize
684 .checked_add(statement.len())
685 .and_then(|v| v.checked_add(1))
686 .and_then(|v| v.checked_add(2))
687 .and_then(|v| v.checked_add(param_formats_size))
688 .and_then(|v| v.checked_add(params_size))
689 .and_then(|v| v.checked_add(result_formats_size))
690 .ok_or(EncodeError::MessageTooLarge(usize::MAX))?;
691 let wire_len = Self::content_len_to_wire_len(content_len)?;
692
693 buf.reserve(1 + 4 + content_len);
694
695 buf.put_u8(b'B');
697
698 Self::put_i32_be(buf, wire_len);
700
701 buf.put_u8(0);
703
704 buf.extend_from_slice(statement.as_bytes());
706 buf.put_u8(0);
707
708 Self::encode_param_formats_bytesmut(buf, param_format);
710
711 let param_count = Self::usize_to_i16(params.len())?;
713 Self::put_i16_be(buf, param_count);
714
715 for param in params {
717 match param {
718 None => Self::put_i32_be(buf, -1),
719 Some(data) => {
720 let data_len = Self::usize_to_i32(data.len())?;
721 Self::put_i32_be(buf, data_len);
722 buf.extend_from_slice(data);
723 }
724 }
725 }
726
727 Self::encode_result_formats_bytesmut(buf, result_format);
729 Ok(())
730 }
731
732 #[inline]
734 pub fn encode_execute_to(buf: &mut BytesMut) {
735 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
737 }
738
739 #[inline]
741 pub fn encode_sync_to(buf: &mut BytesMut) {
742 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
743 }
744}
745
746#[cfg(test)]
747mod tests {
748 use super::*;
749
750 #[test]
752 fn test_encode_query_string() {
753 let sql = "SELECT 1";
754 let bytes = PgEncoder::try_encode_query_string(sql).unwrap();
755
756 assert_eq!(bytes[0], b'Q');
758
759 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
761 assert_eq!(len, 13);
762
763 assert_eq!(&bytes[5..13], b"SELECT 1");
765
766 assert_eq!(bytes[13], 0);
768 }
769
770 #[test]
771 fn test_encode_terminate() {
772 let bytes = PgEncoder::encode_terminate();
773 assert_eq!(bytes.as_ref(), &[b'X', 0, 0, 0, 4]);
774 }
775
776 #[test]
777 fn test_encode_sync() {
778 let bytes = PgEncoder::encode_sync();
779 assert_eq!(bytes.as_ref(), &[b'S', 0, 0, 0, 4]);
780 }
781
782 #[test]
783 fn test_encode_parse() {
784 let bytes = PgEncoder::try_encode_parse("", "SELECT $1", &[]).unwrap();
785
786 assert_eq!(bytes[0], b'P');
788
789 let content = String::from_utf8_lossy(&bytes[5..]);
791 assert!(content.contains("SELECT $1"));
792 }
793
794 #[test]
795 fn test_encode_bind() {
796 let params = vec![
797 Some(b"42".to_vec()),
798 None, ];
800 let bytes = PgEncoder::encode_bind("", "", ¶ms).unwrap();
801
802 assert_eq!(bytes[0], b'B');
804
805 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
807 assert!(len > 4); }
809
810 #[test]
811 fn test_encode_bind_binary_result_format() {
812 let bytes =
813 PgEncoder::encode_bind_with_result_format("", "", &[], PgEncoder::FORMAT_BINARY)
814 .unwrap();
815
816 assert_eq!(&bytes[11..15], &[0, 1, 0, 1]);
819 }
820
821 #[test]
822 fn test_encode_bind_binary_param_and_result_format() {
823 let bytes = PgEncoder::encode_bind_with_formats(
824 "",
825 "",
826 &[],
827 PgEncoder::FORMAT_BINARY,
828 PgEncoder::FORMAT_BINARY,
829 )
830 .unwrap();
831
832 assert_eq!(&bytes[7..11], &[0, 1, 0, 1]);
834 assert_eq!(&bytes[11..13], &[0, 0]);
835 assert_eq!(&bytes[13..17], &[0, 1, 0, 1]);
836 }
837
838 #[test]
839 fn test_encode_execute() {
840 let bytes = PgEncoder::try_encode_execute("", 0).unwrap();
841
842 assert_eq!(bytes[0], b'E');
844
845 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
847 assert_eq!(len, 9);
848 }
849
850 #[test]
851 fn test_encode_execute_negative_max_rows_returns_error() {
852 let err = PgEncoder::try_encode_execute("", -1).expect_err("must reject negative max_rows");
853 assert_eq!(err, EncodeError::InvalidMaxRows(-1));
854 }
855
856 #[test]
857 fn test_encode_extended_query() {
858 let params = vec![Some(b"hello".to_vec())];
859 let bytes = PgEncoder::encode_extended_query("SELECT $1", ¶ms).unwrap();
860
861 assert!(bytes.windows(1).any(|w| w == [b'P']));
863 assert!(bytes.windows(1).any(|w| w == [b'B']));
864 assert!(bytes.windows(1).any(|w| w == [b'E']));
865 assert!(bytes.windows(1).any(|w| w == [b'S']));
866 }
867
868 #[test]
869 fn test_encode_extended_query_binary_result_format() {
870 let bytes = PgEncoder::encode_extended_query_with_result_format(
871 "SELECT 1",
872 &[],
873 PgEncoder::FORMAT_BINARY,
874 )
875 .unwrap();
876
877 let parse_len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]) as usize;
878 let bind_start = 1 + parse_len;
879 assert_eq!(bytes[bind_start], b'B');
880
881 let bind_len = i32::from_be_bytes([
882 bytes[bind_start + 1],
883 bytes[bind_start + 2],
884 bytes[bind_start + 3],
885 bytes[bind_start + 4],
886 ]);
887 assert_eq!(bind_len, 14);
888
889 let bind_content = &bytes[bind_start + 5..bind_start + 1 + bind_len as usize];
890 assert_eq!(&bind_content[6..10], &[0, 1, 0, 1]);
891 }
892
893 #[test]
894 fn test_encode_extended_query_binary_param_and_result_format() {
895 let bytes = PgEncoder::encode_extended_query_with_formats(
896 "SELECT 1",
897 &[],
898 PgEncoder::FORMAT_BINARY,
899 PgEncoder::FORMAT_BINARY,
900 )
901 .unwrap();
902
903 let parse_len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]) as usize;
904 let bind_start = 1 + parse_len;
905 let bind_len = i32::from_be_bytes([
906 bytes[bind_start + 1],
907 bytes[bind_start + 2],
908 bytes[bind_start + 3],
909 bytes[bind_start + 4],
910 ]);
911 assert_eq!(bind_len, 16);
912
913 let bind_content = &bytes[bind_start + 5..bind_start + 1 + bind_len as usize];
914 assert_eq!(&bind_content[2..6], &[0, 1, 0, 1]);
915 assert_eq!(&bind_content[6..8], &[0, 0]);
916 assert_eq!(&bind_content[8..12], &[0, 1, 0, 1]);
917 }
918
919 #[test]
920 fn test_encode_copy_fail() {
921 let bytes = PgEncoder::try_encode_copy_fail("bad data").unwrap();
922 assert_eq!(bytes[0], b'f');
923 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
924 assert_eq!(len as usize, 4 + "bad data".len() + 1);
925 assert_eq!(&bytes[5..13], b"bad data");
926 assert_eq!(bytes[13], 0);
927 }
928
929 #[test]
930 fn test_encode_close_statement() {
931 let bytes = PgEncoder::try_encode_close(false, "my_stmt").unwrap();
932 assert_eq!(bytes[0], b'C');
933 assert_eq!(bytes[5], b'S'); assert_eq!(&bytes[6..13], b"my_stmt");
935 assert_eq!(bytes[13], 0);
936 }
937
938 #[test]
939 fn test_encode_close_portal() {
940 let bytes = PgEncoder::try_encode_close(true, "").unwrap();
941 assert_eq!(bytes[0], b'C');
942 assert_eq!(bytes[5], b'P'); assert_eq!(bytes[6], 0); }
945
946 #[test]
947 fn test_encode_parse_too_many_param_types_returns_error() {
948 let param_types = vec![0u32; (i16::MAX as usize) + 1];
949 let err =
950 PgEncoder::try_encode_parse("s", "SELECT 1", ¶m_types).expect_err("must reject");
951 assert_eq!(err, EncodeError::TooManyParameters(param_types.len()));
952 }
953
954 #[test]
955 fn test_encode_bind_to_binary_result_format() {
956 let mut buf = BytesMut::new();
957 PgEncoder::encode_bind_to_with_result_format(&mut buf, "", &[], PgEncoder::FORMAT_BINARY)
958 .unwrap();
959
960 assert_eq!(&buf[11..15], &[0, 1, 0, 1]);
961 }
962
963 #[test]
964 fn test_encode_bind_to_binary_param_and_result_format() {
965 let mut buf = BytesMut::new();
966 PgEncoder::encode_bind_to_with_formats(
967 &mut buf,
968 "",
969 &[],
970 PgEncoder::FORMAT_BINARY,
971 PgEncoder::FORMAT_BINARY,
972 )
973 .unwrap();
974
975 assert_eq!(&buf[7..11], &[0, 1, 0, 1]);
976 assert_eq!(&buf[11..13], &[0, 0]);
977 assert_eq!(&buf[13..17], &[0, 1, 0, 1]);
978 }
979
980 #[test]
981 fn test_encode_bind_ultra_binary_result_format() {
982 let mut buf = BytesMut::new();
983 PgEncoder::encode_bind_ultra_with_result_format(
984 &mut buf,
985 "",
986 &[],
987 PgEncoder::FORMAT_BINARY,
988 )
989 .unwrap();
990
991 assert_eq!(&buf[11..15], &[0, 1, 0, 1]);
992 }
993
994 #[test]
995 fn test_encode_bind_ultra_binary_param_and_result_format() {
996 let mut buf = BytesMut::new();
997 PgEncoder::encode_bind_ultra_with_formats(
998 &mut buf,
999 "",
1000 &[],
1001 PgEncoder::FORMAT_BINARY,
1002 PgEncoder::FORMAT_BINARY,
1003 )
1004 .unwrap();
1005
1006 assert_eq!(&buf[7..11], &[0, 1, 0, 1]);
1007 assert_eq!(&buf[11..13], &[0, 0]);
1008 assert_eq!(&buf[13..17], &[0, 1, 0, 1]);
1009 }
1010
1011 #[test]
1012 fn test_encode_query_string_with_nul_returns_empty() {
1013 let err =
1014 PgEncoder::try_encode_query_string("select 1\0select 2").expect_err("must reject NUL");
1015 assert_eq!(err, EncodeError::NullByte);
1016 }
1017
1018 #[test]
1019 fn test_encode_parse_with_nul_returns_empty() {
1020 let err = PgEncoder::try_encode_parse("s", "SELECT 1\0", &[]).expect_err("must reject");
1021 assert_eq!(err, EncodeError::NullByte);
1022 }
1023
1024 #[test]
1025 fn test_encode_bind_with_nul_rejected() {
1026 let err = PgEncoder::encode_bind_with_result_format("\0", "", &[], PgEncoder::FORMAT_TEXT)
1027 .expect_err("bind with NUL portal must fail");
1028 assert_eq!(err, EncodeError::NullByte);
1029 }
1030
1031 #[test]
1032 fn test_encode_extended_query_with_nul_rejected() {
1033 let err = PgEncoder::encode_extended_query_with_result_format(
1034 "SELECT 1\0UNION SELECT 2",
1035 &[],
1036 PgEncoder::FORMAT_TEXT,
1037 )
1038 .expect_err("extended query with NUL SQL must fail");
1039 assert_eq!(err, EncodeError::NullByte);
1040 }
1041
1042 #[test]
1043 fn test_encode_copy_fail_with_nul_returns_empty() {
1044 let err = PgEncoder::try_encode_copy_fail("bad\0data").expect_err("must reject");
1045 assert_eq!(err, EncodeError::NullByte);
1046 }
1047}