1use std::{io, marker::PhantomData};
4
5use bytes::{Buf, BufMut, Bytes, BytesMut};
6use tokio_util::codec::{Decoder, Encoder};
7
8use crate::startup::ProtocolVersion;
9
10#[derive(Debug)]
12pub enum Frontend {}
13
14#[derive(Debug)]
16pub enum Backend {}
17
18#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct Frame {
21 pub tag: u8,
23 pub body: Bytes,
25}
26
27pub trait Direction {
29 type Message;
31
32 fn decode(frame: Frame) -> io::Result<Self::Message>;
36}
37
38#[derive(Debug)]
40pub struct PgCodec<D> {
41 max_frame_len: usize,
42 _direction: PhantomData<fn() -> D>,
43}
44
45const MAX_PROTOCOL_FRAME_LEN: usize = i32::MAX as usize + 1;
46pub const DEFAULT_MAX_FRAME_LEN: usize = 16 * 1024 * 1024;
48
49impl<D> Default for PgCodec<D> {
50 fn default() -> Self {
51 Self {
52 max_frame_len: DEFAULT_MAX_FRAME_LEN,
53 _direction: PhantomData,
54 }
55 }
56}
57
58impl<D> PgCodec<D> {
59 pub fn with_max_frame_len(max_frame_len: usize) -> io::Result<Self> {
66 if !(5..=MAX_PROTOCOL_FRAME_LEN).contains(&max_frame_len) {
67 return Err(io::Error::new(
68 io::ErrorKind::InvalidInput,
69 "frame limit is outside PostgreSQL's tagged-frame range",
70 ));
71 }
72 Ok(Self {
73 max_frame_len,
74 _direction: PhantomData,
75 })
76 }
77}
78
79impl<D: Direction> Decoder for PgCodec<D> {
80 type Item = D::Message;
81 type Error = io::Error;
82
83 fn decode(&mut self, source: &mut BytesMut) -> io::Result<Option<Self::Item>> {
84 let Some(frame) = decode_frame(source, self.max_frame_len)? else {
85 return Ok(None);
86 };
87 let tag = frame.tag;
88 D::decode(frame).map(Some).map_err(|error| {
89 io::Error::new(error.kind(), format!("message tag 0x{tag:02x}: {error}"))
90 })
91 }
92}
93
94impl<D> Encoder<Frame> for PgCodec<D> {
95 type Error = io::Error;
96
97 fn encode(&mut self, item: Frame, destination: &mut BytesMut) -> io::Result<()> {
98 let frame_len = item
99 .body
100 .len()
101 .checked_add(5)
102 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "frame too large"))?;
103 if frame_len > self.max_frame_len {
104 return Err(io::Error::new(
105 io::ErrorKind::InvalidInput,
106 "frame exceeds configured limit",
107 ));
108 }
109 let length = item
110 .body
111 .len()
112 .checked_add(4)
113 .and_then(|length| u32::try_from(length).ok())
114 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "frame too large"))?;
115 destination.reserve(item.body.len() + 5);
116 destination.put_u8(item.tag);
117 destination.put_u32(length);
118 destination.extend_from_slice(&item.body);
119 Ok(())
120 }
121}
122
123fn decode_frame(source: &mut BytesMut, max_frame_len: usize) -> io::Result<Option<Frame>> {
124 if source.len() < 5 {
125 source.reserve(5 - source.len());
126 return Ok(None);
127 }
128
129 let length = u32::from_be_bytes(source[1..5].try_into().expect("four-byte slice"));
130 if length < 4 {
131 return Err(io::Error::new(
132 io::ErrorKind::InvalidData,
133 "message length is smaller than its length field",
134 ));
135 }
136 let frame_length = usize::try_from(length)
137 .ok()
138 .and_then(|length| length.checked_add(1))
139 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "message length overflow"))?;
140 if frame_length > MAX_PROTOCOL_FRAME_LEN {
141 return Err(io::Error::new(
142 io::ErrorKind::InvalidData,
143 "message length exceeds PostgreSQL's signed int32 range",
144 ));
145 }
146 if frame_length > max_frame_len {
147 return Err(io::Error::new(
148 io::ErrorKind::InvalidData,
149 "message exceeds configured frame limit",
150 ));
151 }
152 if source.len() < frame_length {
153 source.reserve(frame_length - source.len());
154 return Ok(None);
155 }
156
157 let tag = source[0];
158 let mut bytes = source.split_to(frame_length).freeze();
159 bytes.advance(5);
160 Ok(Some(Frame { tag, body: bytes }))
161}
162
163#[derive(Clone, Eq, PartialEq)]
165pub enum FrontendMessage {
166 Parse(Parse),
168 Bind(Bind),
170 Describe(Describe),
172 Close(Close),
174 Execute(Execute),
176 FunctionCall(FunctionCall),
178 Query(Bytes),
180 Flush,
182 Sync,
184 Terminate,
186 CopyData(Bytes),
188 CopyDone,
190 CopyFail(Bytes),
192 PasswordResponse(Bytes),
194}
195
196impl std::fmt::Debug for FrontendMessage {
197 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 match self {
199 Self::Parse(value) => formatter.debug_tuple("Parse").field(value).finish(),
200 Self::Bind(value) => formatter.debug_tuple("Bind").field(value).finish(),
201 Self::Describe(value) => formatter.debug_tuple("Describe").field(value).finish(),
202 Self::Close(value) => formatter.debug_tuple("Close").field(value).finish(),
203 Self::Execute(value) => formatter.debug_tuple("Execute").field(value).finish(),
204 Self::FunctionCall(value) => {
205 formatter.debug_tuple("FunctionCall").field(value).finish()
206 }
207 Self::Query(value) => formatter.debug_tuple("Query").field(value).finish(),
208 Self::Flush => formatter.write_str("Flush"),
209 Self::Sync => formatter.write_str("Sync"),
210 Self::Terminate => formatter.write_str("Terminate"),
211 Self::CopyData(value) => formatter.debug_tuple("CopyData").field(value).finish(),
212 Self::CopyDone => formatter.write_str("CopyDone"),
213 Self::CopyFail(value) => formatter.debug_tuple("CopyFail").field(value).finish(),
214 Self::PasswordResponse(value) => formatter
215 .debug_tuple("PasswordResponse")
216 .field(&format_args!("[REDACTED; {} bytes]", value.len()))
217 .finish(),
218 }
219 }
220}
221
222impl FrontendMessage {
223 pub fn to_frame(&self) -> io::Result<Frame> {
229 match self {
230 Self::Parse(message) => message.to_frame(),
231 Self::Bind(message) => message.to_frame(),
232 Self::Describe(message) => message.to_frame(),
233 Self::Close(message) => message.to_frame(),
234 Self::Execute(message) => message.to_frame(),
235 Self::FunctionCall(message) => message.to_frame(),
236 Self::Query(query) => cstr_message(b'Q', query),
237 Self::Flush => Ok(empty_message(b'H')),
238 Self::Sync => Ok(empty_message(b'S')),
239 Self::Terminate => Ok(empty_message(b'X')),
240 Self::CopyData(data) => Ok(Frame {
241 tag: b'd',
242 body: data.clone(),
243 }),
244 Self::CopyDone => Ok(empty_message(b'c')),
245 Self::CopyFail(message) => cstr_message(b'f', message),
246 Self::PasswordResponse(data) => Ok(Frame {
247 tag: b'p',
248 body: data.clone(),
249 }),
250 }
251 }
252}
253
254#[derive(Clone, Debug, Eq, PartialEq)]
256pub struct Parse {
257 pub statement: Bytes,
259 pub query: Bytes,
261 pub parameter_types: Vec<u32>,
263}
264
265impl Parse {
266 pub fn to_frame(&self) -> io::Result<Frame> {
272 let mut body = BytesMut::new();
273 put_cstr(&self.statement, &mut body)?;
274 put_cstr(&self.query, &mut body)?;
275 put_count(self.parameter_types.len(), &mut body)?;
276 for oid in &self.parameter_types {
277 body.put_u32(*oid);
278 }
279 Ok(Frame {
280 tag: b'P',
281 body: body.freeze(),
282 })
283 }
284}
285
286#[derive(Clone, Debug, Eq, PartialEq)]
288pub struct Bind {
289 pub portal: Bytes,
291 pub statement: Bytes,
293 pub parameter_formats: Vec<i16>,
295 pub parameters: Vec<Option<Bytes>>,
297 pub result_formats: Vec<i16>,
299}
300
301impl Bind {
302 pub fn to_frame(&self) -> io::Result<Frame> {
308 let mut body = BytesMut::new();
309 put_cstr(&self.portal, &mut body)?;
310 put_cstr(&self.statement, &mut body)?;
311 put_i16_vec(&self.parameter_formats, &mut body)?;
312 put_count(self.parameters.len(), &mut body)?;
313 for parameter in &self.parameters {
314 match parameter {
315 None => body.put_i32(-1),
316 Some(value) => {
317 let length = i32::try_from(value.len())
318 .map_err(|_| invalid_input("Bind parameter is too large"))?;
319 body.put_i32(length);
320 body.extend_from_slice(value);
321 }
322 }
323 }
324 put_i16_vec(&self.result_formats, &mut body)?;
325 Ok(Frame {
326 tag: b'B',
327 body: body.freeze(),
328 })
329 }
330}
331
332#[derive(Clone, Debug, Eq, PartialEq)]
334pub struct Describe {
335 pub target: DescribeTarget,
337 pub name: Bytes,
339}
340
341#[derive(Clone, Copy, Debug, Eq, PartialEq)]
343pub enum DescribeTarget {
344 Statement,
346 Portal,
348}
349
350#[derive(Clone, Debug, Eq, PartialEq)]
352pub struct Close {
353 pub target: DescribeTarget,
355 pub name: Bytes,
357}
358
359#[derive(Clone, Debug, Eq, PartialEq)]
361pub struct Execute {
362 pub portal: Bytes,
364 pub max_rows: i32,
366}
367
368#[derive(Clone, Debug, Eq, PartialEq)]
370pub struct FunctionCall {
371 pub function_oid: u32,
373 pub argument_formats: Vec<i16>,
375 pub arguments: Vec<Option<Bytes>>,
377 pub result_format: i16,
379}
380
381impl Describe {
382 pub fn to_frame(&self) -> io::Result<Frame> {
388 let mut body = BytesMut::new();
389 body.put_u8(match self.target {
390 DescribeTarget::Statement => b'S',
391 DescribeTarget::Portal => b'P',
392 });
393 put_cstr(&self.name, &mut body)?;
394 Ok(Frame {
395 tag: b'D',
396 body: body.freeze(),
397 })
398 }
399}
400
401impl Close {
402 pub fn to_frame(&self) -> io::Result<Frame> {
406 named_target_frame(b'C', self.target, &self.name)
407 }
408}
409
410impl Execute {
411 pub fn to_frame(&self) -> io::Result<Frame> {
415 let mut body = BytesMut::new();
416 put_cstr(&self.portal, &mut body)?;
417 body.put_i32(self.max_rows);
418 Ok(Frame {
419 tag: b'E',
420 body: body.freeze(),
421 })
422 }
423}
424
425impl FunctionCall {
426 pub fn to_frame(&self) -> io::Result<Frame> {
430 let mut body = BytesMut::new();
431 body.put_u32(self.function_oid);
432 put_i16_vec(&self.argument_formats, &mut body)?;
433 put_count(self.arguments.len(), &mut body)?;
434 for argument in &self.arguments {
435 put_nullable(argument.as_ref(), &mut body)?;
436 }
437 body.put_i16(self.result_format);
438 Ok(Frame {
439 tag: b'F',
440 body: body.freeze(),
441 })
442 }
443}
444
445impl Direction for Frontend {
446 type Message = FrontendMessage;
447
448 fn decode(frame: Frame) -> io::Result<Self::Message> {
449 match frame.tag {
450 b'P' => decode_parse(frame.body).map(FrontendMessage::Parse),
451 b'B' => decode_bind(frame.body).map(FrontendMessage::Bind),
452 b'D' => decode_describe(frame.body).map(FrontendMessage::Describe),
453 b'C' => decode_close(frame.body).map(FrontendMessage::Close),
454 b'E' => decode_execute(frame.body).map(FrontendMessage::Execute),
455 b'F' => decode_function_call(frame.body).map(FrontendMessage::FunctionCall),
456 b'H' => decode_empty(&frame.body).map(|()| FrontendMessage::Flush),
457 b'Q' => decode_cstr_body(frame.body).map(FrontendMessage::Query),
458 b'S' => decode_empty(&frame.body).map(|()| FrontendMessage::Sync),
459 b'X' => decode_empty(&frame.body).map(|()| FrontendMessage::Terminate),
460 b'c' => decode_empty(&frame.body).map(|()| FrontendMessage::CopyDone),
461 b'd' => Ok(FrontendMessage::CopyData(frame.body)),
462 b'f' => decode_cstr_body(frame.body).map(FrontendMessage::CopyFail),
463 b'p' => Ok(FrontendMessage::PasswordResponse(frame.body)),
464 tag => Err(unknown_tag("frontend", tag)),
465 }
466 }
467}
468
469#[derive(Clone, Debug, Eq, PartialEq)]
471pub struct RowDescription {
472 pub fields: Vec<FieldDescription>,
474}
475
476#[derive(Clone, Debug, Eq, PartialEq)]
478pub struct FieldDescription {
479 pub name: Bytes,
481 pub table_oid: u32,
483 pub column: i16,
485 pub type_oid: u32,
487 pub type_size: i16,
489 pub type_modifier: i32,
491 pub format: i16,
493}
494
495impl RowDescription {
496 pub fn to_frame(&self) -> io::Result<Frame> {
502 let mut body = BytesMut::new();
503 put_count(self.fields.len(), &mut body)?;
504 for field in &self.fields {
505 put_cstr(&field.name, &mut body)?;
506 body.put_u32(field.table_oid);
507 body.put_i16(field.column);
508 body.put_u32(field.type_oid);
509 body.put_i16(field.type_size);
510 body.put_i32(field.type_modifier);
511 body.put_i16(field.format);
512 }
513 Ok(Frame {
514 tag: b'T',
515 body: body.freeze(),
516 })
517 }
518}
519
520#[derive(Clone, Debug, Eq, PartialEq)]
522pub enum Authentication {
523 Ok,
525 KerberosV5,
527 CleartextPassword,
529 Md5Password {
531 salt: [u8; 4],
533 },
534 Gss,
536 GssContinue(Bytes),
538 Sspi,
540 Sasl {
542 mechanisms: Vec<Bytes>,
544 },
545 SaslContinue(Bytes),
547 SaslFinal(Bytes),
549}
550
551#[derive(Clone, Copy, Debug, Eq, PartialEq)]
553pub enum TransactionStatus {
554 Idle,
556 InTransaction,
558 FailedTransaction,
560}
561
562#[derive(Clone, Debug, Eq, PartialEq)]
564pub struct NegotiateProtocolVersion {
565 pub newest: ProtocolVersion,
567 pub unsupported_options: Vec<Bytes>,
569}
570
571#[derive(Clone, Debug, Eq, PartialEq)]
573pub struct DiagnosticResponse {
574 pub fields: Vec<DiagnosticField>,
576}
577
578#[derive(Clone, Debug, Eq, PartialEq)]
580pub struct DiagnosticField {
581 pub code: u8,
583 pub value: Bytes,
585}
586
587#[derive(Clone, Debug, Eq, PartialEq)]
589pub struct CopyResponse {
590 pub overall_format: u8,
592 pub column_formats: Vec<i16>,
594}
595
596#[derive(Clone, Debug, Eq, PartialEq)]
598pub struct DataRow {
599 pub columns: Vec<Option<Bytes>>,
601}
602
603#[derive(Clone, Debug, Eq, PartialEq)]
605pub enum BackendMessage {
606 RowDescription(RowDescription),
608 Authentication(Authentication),
610 ParseComplete,
612 BindComplete,
614 CloseComplete,
616 CommandComplete(Bytes),
618 CopyData(Bytes),
620 CopyDone,
622 CopyInResponse(CopyResponse),
624 CopyOutResponse(CopyResponse),
626 CopyBothResponse(CopyResponse),
628 DataRow(DataRow),
630 EmptyQueryResponse,
632 ErrorResponse(DiagnosticResponse),
634 NoData,
636 ParameterStatus {
638 name: Bytes,
640 value: Bytes,
642 },
643 NoticeResponse(DiagnosticResponse),
645 NotificationResponse {
647 process_id: u32,
649 channel: Bytes,
651 payload: Bytes,
653 },
654 BackendKeyData {
656 process_id: u32,
658 secret_key: Bytes,
660 },
661 ReadyForQuery(TransactionStatus),
663 ParameterDescription(Vec<u32>),
665 PortalSuspended,
667 FunctionCallResponse(Bytes),
669 NegotiateProtocolVersion(NegotiateProtocolVersion),
671}
672
673impl BackendMessage {
674 pub fn to_frame(&self) -> io::Result<Frame> {
680 match self {
681 Self::RowDescription(message) => message.to_frame(),
682 Self::Authentication(message) => authentication_frame(message),
683 Self::ParseComplete => Ok(empty_message(b'1')),
684 Self::BindComplete => Ok(empty_message(b'2')),
685 Self::CloseComplete => Ok(empty_message(b'3')),
686 Self::CommandComplete(tag) => cstr_message(b'C', tag),
687 Self::CopyData(data) => Ok(Frame {
688 tag: b'd',
689 body: data.clone(),
690 }),
691 Self::CopyDone => Ok(empty_message(b'c')),
692 Self::CopyInResponse(response) => copy_response_frame(b'G', response),
693 Self::CopyOutResponse(response) => copy_response_frame(b'H', response),
694 Self::CopyBothResponse(response) => copy_response_frame(b'W', response),
695 Self::DataRow(row) => row.to_frame(),
696 Self::EmptyQueryResponse => Ok(empty_message(b'I')),
697 Self::ErrorResponse(response) => diagnostic_frame(b'E', response),
698 Self::NoData => Ok(empty_message(b'n')),
699 Self::ParameterStatus { name, value } => {
700 let mut body = BytesMut::new();
701 put_cstr(name, &mut body)?;
702 put_cstr(value, &mut body)?;
703 Ok(Frame {
704 tag: b'S',
705 body: body.freeze(),
706 })
707 }
708 Self::NoticeResponse(response) => diagnostic_frame(b'N', response),
709 Self::NotificationResponse {
710 process_id,
711 channel,
712 payload,
713 } => {
714 let mut body = BytesMut::new();
715 body.put_u32(*process_id);
716 put_cstr(channel, &mut body)?;
717 put_cstr(payload, &mut body)?;
718 Ok(Frame {
719 tag: b'A',
720 body: body.freeze(),
721 })
722 }
723 Self::BackendKeyData {
724 process_id,
725 secret_key,
726 } => {
727 if !(4..=256).contains(&secret_key.len()) {
728 return Err(invalid_input("cancellation key length is outside 4..=256"));
729 }
730 let mut body = BytesMut::with_capacity(4 + secret_key.len());
731 body.put_u32(*process_id);
732 body.extend_from_slice(secret_key);
733 Ok(Frame {
734 tag: b'K',
735 body: body.freeze(),
736 })
737 }
738 Self::ReadyForQuery(status) => Ok(Frame {
739 tag: b'Z',
740 body: Bytes::copy_from_slice(&[status.as_byte()]),
741 }),
742 Self::ParameterDescription(types) => {
743 let mut body = BytesMut::new();
744 put_count(types.len(), &mut body)?;
745 for oid in types {
746 body.put_u32(*oid);
747 }
748 Ok(Frame {
749 tag: b't',
750 body: body.freeze(),
751 })
752 }
753 Self::PortalSuspended => Ok(empty_message(b's')),
754 Self::FunctionCallResponse(data) => Ok(Frame {
755 tag: b'V',
756 body: data.clone(),
757 }),
758 Self::NegotiateProtocolVersion(message) => message.to_frame(),
759 }
760 }
761}
762
763impl TransactionStatus {
764 const fn as_byte(self) -> u8 {
765 match self {
766 Self::Idle => b'I',
767 Self::InTransaction => b'T',
768 Self::FailedTransaction => b'E',
769 }
770 }
771}
772
773impl NegotiateProtocolVersion {
774 pub fn to_frame(&self) -> io::Result<Frame> {
780 let mut body = BytesMut::new();
781 body.put_u32((u32::from(self.newest.major) << 16) | u32::from(self.newest.minor));
782 let count = u32::try_from(self.unsupported_options.len())
783 .map_err(|_| invalid_input("unsupported option count exceeds u32"))?;
784 body.put_u32(count);
785 for option in &self.unsupported_options {
786 put_cstr(option, &mut body)?;
787 }
788 Ok(Frame {
789 tag: b'v',
790 body: body.freeze(),
791 })
792 }
793}
794
795impl DataRow {
796 pub fn to_frame(&self) -> io::Result<Frame> {
800 let mut body = BytesMut::new();
801 put_count(self.columns.len(), &mut body)?;
802 for column in &self.columns {
803 put_nullable(column.as_ref(), &mut body)?;
804 }
805 Ok(Frame {
806 tag: b'D',
807 body: body.freeze(),
808 })
809 }
810}
811
812fn diagnostic_frame(tag: u8, response: &DiagnosticResponse) -> io::Result<Frame> {
813 let mut body = BytesMut::new();
814 for field in &response.fields {
815 if field.code == 0 {
816 return Err(invalid_input("diagnostic field code cannot be zero"));
817 }
818 body.put_u8(field.code);
819 put_cstr(&field.value, &mut body)?;
820 }
821 body.put_u8(0);
822 Ok(Frame {
823 tag,
824 body: body.freeze(),
825 })
826}
827
828fn copy_response_frame(tag: u8, response: &CopyResponse) -> io::Result<Frame> {
829 let mut body = BytesMut::new();
830 body.put_u8(response.overall_format);
831 put_i16_vec(&response.column_formats, &mut body)?;
832 Ok(Frame {
833 tag,
834 body: body.freeze(),
835 })
836}
837
838fn authentication_frame(authentication: &Authentication) -> io::Result<Frame> {
839 let mut body = BytesMut::new();
840 match authentication {
841 Authentication::Ok => body.put_u32(0),
842 Authentication::KerberosV5 => body.put_u32(2),
843 Authentication::CleartextPassword => body.put_u32(3),
844 Authentication::Md5Password { salt } => {
845 body.put_u32(5);
846 body.extend_from_slice(salt);
847 }
848 Authentication::Gss => body.put_u32(7),
849 Authentication::GssContinue(data) => {
850 body.put_u32(8);
851 body.extend_from_slice(data);
852 }
853 Authentication::Sspi => body.put_u32(9),
854 Authentication::Sasl { mechanisms } => {
855 body.put_u32(10);
856 for mechanism in mechanisms {
857 put_cstr(mechanism, &mut body)?;
858 }
859 body.put_u8(0);
860 }
861 Authentication::SaslContinue(data) => {
862 body.put_u32(11);
863 body.extend_from_slice(data);
864 }
865 Authentication::SaslFinal(data) => {
866 body.put_u32(12);
867 body.extend_from_slice(data);
868 }
869 }
870 Ok(Frame {
871 tag: b'R',
872 body: body.freeze(),
873 })
874}
875
876impl Direction for Backend {
877 type Message = BackendMessage;
878
879 fn decode(frame: Frame) -> io::Result<Self::Message> {
880 match frame.tag {
881 b'1' => decode_empty(&frame.body).map(|()| BackendMessage::ParseComplete),
882 b'2' => decode_empty(&frame.body).map(|()| BackendMessage::BindComplete),
883 b'3' => decode_empty(&frame.body).map(|()| BackendMessage::CloseComplete),
884 b'C' => decode_cstr_body(frame.body).map(BackendMessage::CommandComplete),
885 b'c' => decode_empty(&frame.body).map(|()| BackendMessage::CopyDone),
886 b'd' => Ok(BackendMessage::CopyData(frame.body)),
887 b'D' => decode_data_row(frame.body).map(BackendMessage::DataRow),
888 b'E' => decode_diagnostic(frame.body).map(BackendMessage::ErrorResponse),
889 b'G' => decode_copy_response(frame.body).map(BackendMessage::CopyInResponse),
890 b'H' => decode_copy_response(frame.body).map(BackendMessage::CopyOutResponse),
891 b'I' => decode_empty(&frame.body).map(|()| BackendMessage::EmptyQueryResponse),
892 b'n' => decode_empty(&frame.body).map(|()| BackendMessage::NoData),
893 b's' => decode_empty(&frame.body).map(|()| BackendMessage::PortalSuspended),
894 b't' => {
895 decode_parameter_description(frame.body).map(BackendMessage::ParameterDescription)
896 }
897 b'T' => decode_row_description(frame.body).map(BackendMessage::RowDescription),
898 b'V' => Ok(BackendMessage::FunctionCallResponse(frame.body)),
899 b'W' => decode_copy_response(frame.body).map(BackendMessage::CopyBothResponse),
900 b'R' => decode_authentication(frame.body).map(BackendMessage::Authentication),
901 b'S' => decode_parameter_status(frame.body),
902 b'N' => decode_diagnostic(frame.body).map(BackendMessage::NoticeResponse),
903 b'A' => decode_notification(frame.body),
904 b'K' => decode_backend_key_data(frame.body),
905 b'Z' => decode_ready(frame.body),
906 b'v' => decode_negotiate_protocol_version(frame.body),
907 tag => Err(unknown_tag("backend", tag)),
908 }
909 }
910}
911
912fn decode_authentication(mut body: Bytes) -> io::Result<Authentication> {
913 let kind = take_u32(&mut body)?;
914 let auth = match kind {
915 0 => Authentication::Ok,
916 2 => Authentication::KerberosV5,
917 3 => Authentication::CleartextPassword,
918 5 => {
919 require(&body, 4)?;
920 let salt = body.split_to(4);
921 Authentication::Md5Password {
922 salt: salt[..].try_into().expect("four-byte slice"),
923 }
924 }
925 7 => Authentication::Gss,
926 8 => Authentication::GssContinue(body.split_to(body.len())),
927 9 => Authentication::Sspi,
928 10 => {
929 let mut mechanisms = Vec::new();
930 while !body.is_empty() && body[0] != 0 {
931 mechanisms.push(take_cstr(&mut body)?);
932 }
933 require(&body, 1)?;
934 body.advance(1);
935 Authentication::Sasl { mechanisms }
936 }
937 11 => Authentication::SaslContinue(body.split_to(body.len())),
938 12 => Authentication::SaslFinal(body.split_to(body.len())),
939 _ => return Err(invalid("unknown authentication request")),
940 };
941 require_empty(&body)?;
942 Ok(auth)
943}
944
945fn decode_parameter_status(mut body: Bytes) -> io::Result<BackendMessage> {
946 let name = take_cstr(&mut body)?;
947 let value = take_cstr(&mut body)?;
948 require_empty(&body)?;
949 Ok(BackendMessage::ParameterStatus { name, value })
950}
951
952fn decode_notification(mut body: Bytes) -> io::Result<BackendMessage> {
953 let process_id = take_u32(&mut body)?;
954 let channel = take_cstr(&mut body)?;
955 let payload = take_cstr(&mut body)?;
956 require_empty(&body)?;
957 Ok(BackendMessage::NotificationResponse {
958 process_id,
959 channel,
960 payload,
961 })
962}
963
964fn decode_backend_key_data(mut body: Bytes) -> io::Result<BackendMessage> {
965 let process_id = take_u32(&mut body)?;
966 if !(4..=256).contains(&body.len()) {
967 return Err(invalid("cancellation key length is outside 4..=256"));
968 }
969 let secret_key = body;
970 Ok(BackendMessage::BackendKeyData {
971 process_id,
972 secret_key,
973 })
974}
975
976fn decode_ready(mut body: Bytes) -> io::Result<BackendMessage> {
977 require(&body, 1)?;
978 let status = match body.get_u8() {
979 b'I' => TransactionStatus::Idle,
980 b'T' => TransactionStatus::InTransaction,
981 b'E' => TransactionStatus::FailedTransaction,
982 _ => return Err(invalid("unknown transaction status")),
983 };
984 require_empty(&body)?;
985 Ok(BackendMessage::ReadyForQuery(status))
986}
987
988fn decode_negotiate_protocol_version(mut body: Bytes) -> io::Result<BackendMessage> {
989 let newest = take_u32(&mut body)?;
990 let major = u16::try_from(newest >> 16).map_err(|_| invalid("protocol major overflow"))?;
991 let minor = u16::try_from(newest & 0xffff).map_err(|_| invalid("protocol minor overflow"))?;
992 let count = take_u32(&mut body)?;
993 let capacity = usize::try_from(count).map_err(|_| invalid("option count overflow"))?;
994 require_collection_bytes(capacity, body.len(), 1, "unsupported option count")?;
995 let mut unsupported_options = Vec::with_capacity(capacity);
996 for _ in 0..count {
997 unsupported_options.push(take_cstr(&mut body)?);
998 }
999 require_empty(&body)?;
1000 Ok(BackendMessage::NegotiateProtocolVersion(
1001 NegotiateProtocolVersion {
1002 newest: ProtocolVersion { major, minor },
1003 unsupported_options,
1004 },
1005 ))
1006}
1007
1008fn decode_parse(mut body: Bytes) -> io::Result<Parse> {
1009 let statement = take_cstr(&mut body)?;
1010 let query = take_cstr(&mut body)?;
1011 let count = take_u16(&mut body)?;
1012 require_collection_bytes(usize::from(count), body.len(), 4, "parameter type count")?;
1013 let mut parameter_types = Vec::with_capacity(usize::from(count));
1014 for _ in 0..count {
1015 parameter_types.push(take_u32(&mut body)?);
1016 }
1017 require_empty(&body)?;
1018 Ok(Parse {
1019 statement,
1020 query,
1021 parameter_types,
1022 })
1023}
1024
1025fn decode_bind(mut body: Bytes) -> io::Result<Bind> {
1026 let portal = take_cstr(&mut body)?;
1027 let statement = take_cstr(&mut body)?;
1028 let parameter_formats = take_i16_vec(&mut body)?;
1029 let parameter_count = take_u16(&mut body)?;
1030 require_collection_bytes(
1031 usize::from(parameter_count),
1032 body.len(),
1033 4,
1034 "parameter count",
1035 )?;
1036 let mut parameters = Vec::with_capacity(usize::from(parameter_count));
1037 for _ in 0..parameter_count {
1038 let length = take_i32(&mut body)?;
1039 if length == -1 {
1040 parameters.push(None);
1041 } else {
1042 let length =
1043 usize::try_from(length).map_err(|_| invalid("negative parameter length"))?;
1044 require(&body, length)?;
1045 parameters.push(Some(body.split_to(length)));
1046 }
1047 }
1048 let result_formats = take_i16_vec(&mut body)?;
1049 require_empty(&body)?;
1050 Ok(Bind {
1051 portal,
1052 statement,
1053 parameter_formats,
1054 parameters,
1055 result_formats,
1056 })
1057}
1058
1059fn decode_describe(mut body: Bytes) -> io::Result<Describe> {
1060 let target = take_target(&mut body)?;
1061 let name = take_cstr(&mut body)?;
1062 require_empty(&body)?;
1063 Ok(Describe { target, name })
1064}
1065
1066fn decode_data_row(mut body: Bytes) -> io::Result<DataRow> {
1067 let count = take_u16(&mut body)?;
1068 require_collection_bytes(usize::from(count), body.len(), 4, "column count")?;
1069 let mut columns = Vec::with_capacity(usize::from(count));
1070 for _ in 0..count {
1071 columns.push(take_nullable(&mut body)?);
1072 }
1073 require_empty(&body)?;
1074 Ok(DataRow { columns })
1075}
1076
1077fn decode_diagnostic(mut body: Bytes) -> io::Result<DiagnosticResponse> {
1078 let mut fields = Vec::new();
1079 loop {
1080 require(&body, 1)?;
1081 let code = body.get_u8();
1082 if code == 0 {
1083 break;
1084 }
1085 fields.push(DiagnosticField {
1086 code,
1087 value: take_cstr(&mut body)?,
1088 });
1089 }
1090 require_empty(&body)?;
1091 Ok(DiagnosticResponse { fields })
1092}
1093
1094fn decode_copy_response(mut body: Bytes) -> io::Result<CopyResponse> {
1095 require(&body, 1)?;
1096 let overall_format = body.get_u8();
1097 let column_formats = take_i16_vec(&mut body)?;
1098 require_empty(&body)?;
1099 Ok(CopyResponse {
1100 overall_format,
1101 column_formats,
1102 })
1103}
1104
1105fn decode_parameter_description(mut body: Bytes) -> io::Result<Vec<u32>> {
1106 let count = take_u16(&mut body)?;
1107 require_collection_bytes(usize::from(count), body.len(), 4, "parameter type count")?;
1108 let mut types = Vec::with_capacity(usize::from(count));
1109 for _ in 0..count {
1110 types.push(take_u32(&mut body)?);
1111 }
1112 require_empty(&body)?;
1113 Ok(types)
1114}
1115
1116fn decode_close(mut body: Bytes) -> io::Result<Close> {
1117 let target = take_target(&mut body)?;
1118 let name = take_cstr(&mut body)?;
1119 require_empty(&body)?;
1120 Ok(Close { target, name })
1121}
1122
1123fn decode_execute(mut body: Bytes) -> io::Result<Execute> {
1124 let portal = take_cstr(&mut body)?;
1125 let max_rows = take_i32(&mut body)?;
1126 require_empty(&body)?;
1127 Ok(Execute { portal, max_rows })
1128}
1129
1130fn decode_function_call(mut body: Bytes) -> io::Result<FunctionCall> {
1131 let function_oid = take_u32(&mut body)?;
1132 let argument_formats = take_i16_vec(&mut body)?;
1133 let count = take_u16(&mut body)?;
1134 require_collection_bytes(usize::from(count), body.len(), 4, "argument count")?;
1135 let mut arguments = Vec::with_capacity(usize::from(count));
1136 for _ in 0..count {
1137 arguments.push(take_nullable(&mut body)?);
1138 }
1139 let result_format = take_i16(&mut body)?;
1140 require_empty(&body)?;
1141 Ok(FunctionCall {
1142 function_oid,
1143 argument_formats,
1144 arguments,
1145 result_format,
1146 })
1147}
1148
1149fn decode_cstr_body(mut body: Bytes) -> io::Result<Bytes> {
1150 let value = take_cstr(&mut body)?;
1151 require_empty(&body)?;
1152 Ok(value)
1153}
1154
1155fn decode_empty(body: &Bytes) -> io::Result<()> {
1156 require_empty(body)
1157}
1158
1159fn take_target(body: &mut Bytes) -> io::Result<DescribeTarget> {
1160 require(body, 1)?;
1161 match body.get_u8() {
1162 b'S' => Ok(DescribeTarget::Statement),
1163 b'P' => Ok(DescribeTarget::Portal),
1164 _ => Err(invalid("invalid statement or portal target")),
1165 }
1166}
1167
1168fn decode_row_description(mut body: Bytes) -> io::Result<RowDescription> {
1169 let count = take_u16(&mut body)?;
1170 require_collection_bytes(usize::from(count), body.len(), 19, "field count")?;
1171 let mut fields = Vec::with_capacity(usize::from(count));
1172 for _ in 0..count {
1173 fields.push(FieldDescription {
1174 name: take_cstr(&mut body)?,
1175 table_oid: take_u32(&mut body)?,
1176 column: take_i16(&mut body)?,
1177 type_oid: take_u32(&mut body)?,
1178 type_size: take_i16(&mut body)?,
1179 type_modifier: take_i32(&mut body)?,
1180 format: take_i16(&mut body)?,
1181 });
1182 }
1183 require_empty(&body)?;
1184 Ok(RowDescription { fields })
1185}
1186
1187fn take_i16_vec(body: &mut Bytes) -> io::Result<Vec<i16>> {
1188 let count = take_u16(body)?;
1189 require_collection_bytes(usize::from(count), body.len(), 2, "format count")?;
1190 (0..count).map(|_| take_i16(body)).collect()
1191}
1192
1193fn require_collection_bytes(
1194 count: usize,
1195 remaining: usize,
1196 minimum_item_len: usize,
1197 description: &str,
1198) -> io::Result<()> {
1199 let minimum_len = count.checked_mul(minimum_item_len).ok_or_else(|| {
1200 io::Error::new(
1201 io::ErrorKind::InvalidData,
1202 format!("{description} overflows message size"),
1203 )
1204 })?;
1205 if minimum_len > remaining {
1206 return Err(io::Error::new(
1207 io::ErrorKind::InvalidData,
1208 format!("{description} exceeds remaining message body"),
1209 ));
1210 }
1211 Ok(())
1212}
1213
1214fn take_nullable(body: &mut Bytes) -> io::Result<Option<Bytes>> {
1215 let length = take_i32(body)?;
1216 if length == -1 {
1217 return Ok(None);
1218 }
1219 let length = usize::try_from(length).map_err(|_| invalid("negative value length"))?;
1220 require(body, length)?;
1221 Ok(Some(body.split_to(length)))
1222}
1223
1224fn put_i16_vec(values: &[i16], body: &mut BytesMut) -> io::Result<()> {
1225 put_count(values.len(), body)?;
1226 for value in values {
1227 body.put_i16(*value);
1228 }
1229 Ok(())
1230}
1231
1232fn put_nullable(value: Option<&Bytes>, body: &mut BytesMut) -> io::Result<()> {
1233 match value {
1234 None => body.put_i32(-1),
1235 Some(value) => {
1236 let length =
1237 i32::try_from(value.len()).map_err(|_| invalid_input("value is too large"))?;
1238 body.put_i32(length);
1239 body.extend_from_slice(value);
1240 }
1241 }
1242 Ok(())
1243}
1244
1245fn put_count(count: usize, body: &mut BytesMut) -> io::Result<()> {
1246 let count =
1247 u16::try_from(count).map_err(|_| invalid_input("message item count exceeds u16"))?;
1248 body.put_u16(count);
1249 Ok(())
1250}
1251
1252fn put_cstr(value: &[u8], body: &mut BytesMut) -> io::Result<()> {
1253 if value.contains(&0) {
1254 return Err(invalid_input("message string contains a NUL byte"));
1255 }
1256 body.extend_from_slice(value);
1257 body.put_u8(0);
1258 Ok(())
1259}
1260
1261fn named_target_frame(tag: u8, target: DescribeTarget, name: &[u8]) -> io::Result<Frame> {
1262 let mut body = BytesMut::new();
1263 body.put_u8(match target {
1264 DescribeTarget::Statement => b'S',
1265 DescribeTarget::Portal => b'P',
1266 });
1267 put_cstr(name, &mut body)?;
1268 Ok(Frame {
1269 tag,
1270 body: body.freeze(),
1271 })
1272}
1273
1274fn cstr_message(tag: u8, value: &[u8]) -> io::Result<Frame> {
1275 let mut body = BytesMut::new();
1276 put_cstr(value, &mut body)?;
1277 Ok(Frame {
1278 tag,
1279 body: body.freeze(),
1280 })
1281}
1282
1283fn empty_message(tag: u8) -> Frame {
1284 Frame {
1285 tag,
1286 body: Bytes::new(),
1287 }
1288}
1289
1290fn take_cstr(body: &mut Bytes) -> io::Result<Bytes> {
1291 let end = body
1292 .iter()
1293 .position(|byte| *byte == 0)
1294 .ok_or_else(|| invalid("unterminated string"))?;
1295 let value = body.split_to(end);
1296 body.advance(1);
1297 Ok(value)
1298}
1299
1300fn take_u16(body: &mut Bytes) -> io::Result<u16> {
1301 require(body, 2)?;
1302 Ok(body.get_u16())
1303}
1304
1305fn take_i16(body: &mut Bytes) -> io::Result<i16> {
1306 require(body, 2)?;
1307 Ok(body.get_i16())
1308}
1309
1310fn take_u32(body: &mut Bytes) -> io::Result<u32> {
1311 require(body, 4)?;
1312 Ok(body.get_u32())
1313}
1314
1315fn take_i32(body: &mut Bytes) -> io::Result<i32> {
1316 require(body, 4)?;
1317 Ok(body.get_i32())
1318}
1319
1320fn require(body: &Bytes, length: usize) -> io::Result<()> {
1321 if body.len() < length {
1322 Err(invalid("truncated message body"))
1323 } else {
1324 Ok(())
1325 }
1326}
1327
1328fn require_empty(body: &Bytes) -> io::Result<()> {
1329 if body.is_empty() {
1330 Ok(())
1331 } else {
1332 Err(invalid("trailing message bytes"))
1333 }
1334}
1335
1336fn invalid(message: &'static str) -> io::Error {
1337 io::Error::new(io::ErrorKind::InvalidData, message)
1338}
1339
1340fn invalid_input(message: &'static str) -> io::Error {
1341 io::Error::new(io::ErrorKind::InvalidInput, message)
1342}
1343
1344fn unknown_tag(direction: &str, tag: u8) -> io::Error {
1345 io::Error::new(
1346 io::ErrorKind::InvalidData,
1347 format!("unknown {direction} message tag 0x{tag:02x}"),
1348 )
1349}
1350
1351#[cfg(test)]
1352mod tests {
1353 use super::*;
1354
1355 #[test]
1356 fn direction_disambiguates_s_tag() {
1357 let frontend_frame = Frame {
1358 tag: b'S',
1359 body: Bytes::new(),
1360 };
1361 assert!(matches!(
1362 Frontend::decode(frontend_frame),
1363 Ok(FrontendMessage::Sync)
1364 ));
1365 assert_eq!(
1366 Backend::decode(Frame {
1367 tag: b'S',
1368 body: Bytes::from_static(b"client_encoding\0UTF8\0"),
1369 })
1370 .expect("valid ParameterStatus"),
1371 BackendMessage::ParameterStatus {
1372 name: Bytes::from_static(b"client_encoding"),
1373 value: Bytes::from_static(b"UTF8"),
1374 }
1375 );
1376 }
1377
1378 #[test]
1379 fn parse_is_losslessly_structured() {
1380 let mut bytes = BytesMut::from(&b"P\0\0\0\x19stmt\0select $1\0\0\x01\0\0\0\x17"[..]);
1381 let original = bytes.clone();
1382 let message = PgCodec::<Frontend>::default()
1383 .decode(&mut bytes)
1384 .expect("valid frame")
1385 .expect("complete frame");
1386 let expected = FrontendMessage::Parse(Parse {
1387 statement: Bytes::from_static(b"stmt"),
1388 query: Bytes::from_static(b"select $1"),
1389 parameter_types: vec![23],
1390 });
1391 assert_eq!(message, expected);
1392
1393 let FrontendMessage::Parse(parsed) = message else {
1394 unreachable!()
1395 };
1396 let frame = parsed.to_frame().expect("reconstructable Parse");
1397 let mut encoded = BytesMut::new();
1398 PgCodec::<Frontend>::default()
1399 .encode(frame, &mut encoded)
1400 .expect("encodable frame");
1401 assert_eq!(encoded, original);
1402 }
1403
1404 #[test]
1405 fn incomplete_frame_does_not_consume_input() {
1406 let mut bytes = BytesMut::from(&b"S\0\0\0\x04"[..4]);
1407 let original = bytes.clone();
1408 assert!(
1409 PgCodec::<Frontend>::default()
1410 .decode(&mut bytes)
1411 .expect("incomplete input is not an error")
1412 .is_none()
1413 );
1414 assert_eq!(bytes, original);
1415 }
1416
1417 #[test]
1418 fn frame_limits_reject_oversized_input_before_allocation() {
1419 let mut codec = PgCodec::<Frontend>::with_max_frame_len(9).unwrap();
1420 let mut oversized = BytesMut::from(&b"Q\0\0\0\x09"[..]);
1421 let error = codec.decode(&mut oversized).unwrap_err();
1422 assert_eq!(error.kind(), io::ErrorKind::InvalidData);
1423 assert_eq!(oversized.len(), 5);
1424
1425 let mut signed_overflow = BytesMut::from(&[b'Q', 0x80, 0, 0, 0][..]);
1426 let error = PgCodec::<Frontend>::default()
1427 .decode(&mut signed_overflow)
1428 .unwrap_err();
1429 assert_eq!(error.kind(), io::ErrorKind::InvalidData);
1430
1431 let error = codec
1432 .encode(
1433 Frame {
1434 tag: b'Q',
1435 body: Bytes::from_static(b"12345"),
1436 },
1437 &mut BytesMut::new(),
1438 )
1439 .unwrap_err();
1440 assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
1441 }
1442
1443 #[test]
1444 fn counted_backend_fields_are_bounded_before_allocation() {
1445 let mut input = BytesMut::from(
1449 &[
1450 b'v', 0, 0, 0, 43, 0, 0, 64, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1451 32, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0,
1452 152,
1453 ][..],
1454 );
1455
1456 let error = PgCodec::<Backend>::default()
1457 .decode(&mut input)
1458 .expect_err("impossible option count must be rejected");
1459
1460 assert_eq!(error.kind(), io::ErrorKind::InvalidData);
1461 assert!(
1462 error
1463 .to_string()
1464 .contains("unsupported option count exceeds remaining message body")
1465 );
1466 }
1467
1468 #[test]
1469 fn default_frame_limit_is_network_safe_and_configurable() {
1470 let mut input = BytesMut::from(&[b'Q', 1, 0, 0, 4][..]);
1471 let error = PgCodec::<Frontend>::default()
1472 .decode(&mut input)
1473 .unwrap_err();
1474 assert_eq!(error.kind(), io::ErrorKind::InvalidData);
1475 assert!(error.to_string().contains("configured frame limit"));
1476
1477 assert!(PgCodec::<Frontend>::with_max_frame_len(MAX_PROTOCOL_FRAME_LEN).is_ok());
1478 }
1479
1480 #[test]
1481 fn bind_round_trips_nulls_formats_and_values() {
1482 let bind = Bind {
1483 portal: Bytes::from_static(b"portal"),
1484 statement: Bytes::from_static(b"statement"),
1485 parameter_formats: vec![1, 0],
1486 parameters: vec![None, Some(Bytes::from_static(b"value"))],
1487 result_formats: vec![1],
1488 };
1489 let frame = bind.to_frame().expect("valid Bind");
1490 assert_eq!(
1491 Frontend::decode(frame).expect("decodable Bind"),
1492 FrontendMessage::Bind(bind)
1493 );
1494 }
1495
1496 #[test]
1497 fn row_description_round_trips_all_metadata() {
1498 let description = RowDescription {
1499 fields: vec![FieldDescription {
1500 name: Bytes::from_static(b"answer"),
1501 table_oid: 16_384,
1502 column: 2,
1503 type_oid: 23,
1504 type_size: 4,
1505 type_modifier: -1,
1506 format: 1,
1507 }],
1508 };
1509 let frame = description.to_frame().expect("valid RowDescription");
1510 assert_eq!(
1511 Backend::decode(frame).expect("decodable RowDescription"),
1512 BackendMessage::RowDescription(description)
1513 );
1514 }
1515
1516 #[test]
1517 fn frontend_message_family_round_trips_structurally() {
1518 let messages = vec![
1519 FrontendMessage::Close(Close {
1520 target: DescribeTarget::Portal,
1521 name: Bytes::from_static(b"p"),
1522 }),
1523 FrontendMessage::Execute(Execute {
1524 portal: Bytes::from_static(b"p"),
1525 max_rows: 10,
1526 }),
1527 FrontendMessage::FunctionCall(FunctionCall {
1528 function_oid: 42,
1529 argument_formats: vec![1],
1530 arguments: vec![Some(Bytes::from_static(b"arg")), None],
1531 result_format: 1,
1532 }),
1533 FrontendMessage::Query(Bytes::from_static(b"select 1")),
1534 FrontendMessage::Flush,
1535 FrontendMessage::Sync,
1536 FrontendMessage::Terminate,
1537 FrontendMessage::CopyData(Bytes::from_static(b"row\n")),
1538 FrontendMessage::CopyDone,
1539 FrontendMessage::CopyFail(Bytes::from_static(b"cancelled")),
1540 FrontendMessage::PasswordResponse(Bytes::from_static(b"opaque response")),
1541 ];
1542 for message in messages {
1543 let frame = message
1544 .to_frame()
1545 .expect("reconstructable frontend message");
1546 assert_eq!(
1547 Frontend::decode(frame).expect("decodable frontend message"),
1548 message
1549 );
1550 }
1551 }
1552
1553 #[test]
1554 fn backend_message_family_round_trips_structurally() {
1555 let diagnostic = DiagnosticResponse {
1556 fields: vec![
1557 DiagnosticField {
1558 code: b'S',
1559 value: Bytes::from_static(b"ERROR"),
1560 },
1561 DiagnosticField {
1562 code: b'M',
1563 value: Bytes::from_static(b"rewritable message"),
1564 },
1565 ],
1566 };
1567 let copy = CopyResponse {
1568 overall_format: 0,
1569 column_formats: vec![0, 1],
1570 };
1571 let messages = vec![
1572 BackendMessage::ParseComplete,
1573 BackendMessage::BindComplete,
1574 BackendMessage::CloseComplete,
1575 BackendMessage::CommandComplete(Bytes::from_static(b"SELECT 1")),
1576 BackendMessage::CopyData(Bytes::from_static(b"row\n")),
1577 BackendMessage::CopyDone,
1578 BackendMessage::CopyInResponse(copy.clone()),
1579 BackendMessage::CopyOutResponse(copy.clone()),
1580 BackendMessage::CopyBothResponse(copy),
1581 BackendMessage::DataRow(DataRow {
1582 columns: vec![Some(Bytes::from_static(b"42")), None],
1583 }),
1584 BackendMessage::EmptyQueryResponse,
1585 BackendMessage::ErrorResponse(diagnostic.clone()),
1586 BackendMessage::NoticeResponse(diagnostic),
1587 BackendMessage::NoData,
1588 BackendMessage::ParameterDescription(vec![23, 25]),
1589 BackendMessage::PortalSuspended,
1590 BackendMessage::FunctionCallResponse(Bytes::from_static(b"result")),
1591 ];
1592 for message in messages {
1593 let frame = message.to_frame().expect("reconstructable backend message");
1594 assert_eq!(
1595 Backend::decode(frame).expect("decodable backend message"),
1596 message
1597 );
1598 }
1599 }
1600}