postgres_protocol/message/
backend.rs

1#![allow(missing_docs)]
2
3use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
4use bytes::{Bytes, BytesMut};
5use fallible_iterator::FallibleIterator;
6use memchr::memchr;
7use std::cmp;
8use std::io::{self, Read};
9use std::ops::Range;
10use std::str;
11
12use crate::Oid;
13
14pub const PARSE_COMPLETE_TAG: u8 = b'1';
15pub const BIND_COMPLETE_TAG: u8 = b'2';
16pub const CLOSE_COMPLETE_TAG: u8 = b'3';
17pub const NOTIFICATION_RESPONSE_TAG: u8 = b'A';
18pub const COPY_DONE_TAG: u8 = b'c';
19pub const COMMAND_COMPLETE_TAG: u8 = b'C';
20pub const COPY_DATA_TAG: u8 = b'd';
21pub const DATA_ROW_TAG: u8 = b'D';
22pub const ERROR_RESPONSE_TAG: u8 = b'E';
23pub const COPY_IN_RESPONSE_TAG: u8 = b'G';
24pub const COPY_OUT_RESPONSE_TAG: u8 = b'H';
25pub const COPY_BOTH_RESPONSE_TAG: u8 = b'W';
26pub const EMPTY_QUERY_RESPONSE_TAG: u8 = b'I';
27pub const BACKEND_KEY_DATA_TAG: u8 = b'K';
28pub const NO_DATA_TAG: u8 = b'n';
29pub const NOTICE_RESPONSE_TAG: u8 = b'N';
30pub const AUTHENTICATION_TAG: u8 = b'R';
31pub const PORTAL_SUSPENDED_TAG: u8 = b's';
32pub const PARAMETER_STATUS_TAG: u8 = b'S';
33pub const PARAMETER_DESCRIPTION_TAG: u8 = b't';
34pub const ROW_DESCRIPTION_TAG: u8 = b'T';
35pub const READY_FOR_QUERY_TAG: u8 = b'Z';
36
37#[derive(Debug, Copy, Clone)]
38pub struct Header {
39    tag: u8,
40    len: i32,
41}
42
43#[allow(clippy::len_without_is_empty)]
44impl Header {
45    #[inline]
46    pub fn parse(buf: &[u8]) -> io::Result<Option<Header>> {
47        if buf.len() < 5 {
48            return Ok(None);
49        }
50
51        let tag = buf[0];
52        let len = BigEndian::read_i32(&buf[1..]);
53
54        if len < 4 {
55            return Err(io::Error::new(
56                io::ErrorKind::InvalidData,
57                "invalid message length: header length < 4",
58            ));
59        }
60
61        Ok(Some(Header { tag, len }))
62    }
63
64    #[inline]
65    pub fn tag(self) -> u8 {
66        self.tag
67    }
68
69    #[inline]
70    pub fn len(self) -> i32 {
71        self.len
72    }
73}
74
75/// An enum representing Postgres backend messages.
76#[non_exhaustive]
77pub enum Message {
78    AuthenticationCleartextPassword,
79    AuthenticationGss,
80    AuthenticationKerberosV5,
81    AuthenticationMd5Password(AuthenticationMd5PasswordBody),
82    AuthenticationOk,
83    AuthenticationScmCredential,
84    AuthenticationSspi,
85    AuthenticationGssContinue(AuthenticationGssContinueBody),
86    AuthenticationSasl(AuthenticationSaslBody),
87    AuthenticationSaslContinue(AuthenticationSaslContinueBody),
88    AuthenticationSaslFinal(AuthenticationSaslFinalBody),
89    BackendKeyData(BackendKeyDataBody),
90    BindComplete,
91    CloseComplete,
92    CommandComplete(CommandCompleteBody),
93    CopyData(CopyDataBody),
94    CopyDone,
95    CopyInResponse(CopyInResponseBody),
96    CopyOutResponse(CopyOutResponseBody),
97    CopyBothResponse(CopyBothResponseBody),
98    DataRow(DataRowBody),
99    EmptyQueryResponse,
100    ErrorResponse(ErrorResponseBody),
101    NoData,
102    NoticeResponse(NoticeResponseBody),
103    NotificationResponse(NotificationResponseBody),
104    ParameterDescription(ParameterDescriptionBody),
105    ParameterStatus(ParameterStatusBody),
106    ParseComplete,
107    PortalSuspended,
108    ReadyForQuery(ReadyForQueryBody),
109    RowDescription(RowDescriptionBody),
110}
111
112impl Message {
113    #[inline]
114    pub fn parse(buf: &mut BytesMut) -> io::Result<Option<Message>> {
115        if buf.len() < 5 {
116            let to_read = 5 - buf.len();
117            buf.reserve(to_read);
118            return Ok(None);
119        }
120
121        let tag = buf[0];
122        let len = (&buf[1..5]).read_u32::<BigEndian>().unwrap();
123
124        if len < 4 {
125            return Err(io::Error::new(
126                io::ErrorKind::InvalidInput,
127                "invalid message length: parsing u32",
128            ));
129        }
130
131        let total_len = len as usize + 1;
132        if buf.len() < total_len {
133            let to_read = total_len - buf.len();
134            buf.reserve(to_read);
135            return Ok(None);
136        }
137
138        let mut buf = Buffer {
139            bytes: buf.split_to(total_len).freeze(),
140            idx: 5,
141        };
142
143        let message = match tag {
144            PARSE_COMPLETE_TAG => Message::ParseComplete,
145            BIND_COMPLETE_TAG => Message::BindComplete,
146            CLOSE_COMPLETE_TAG => Message::CloseComplete,
147            NOTIFICATION_RESPONSE_TAG => {
148                let process_id = buf.read_i32::<BigEndian>()?;
149                let channel = buf.read_cstr()?;
150                let message = buf.read_cstr()?;
151                Message::NotificationResponse(NotificationResponseBody {
152                    process_id,
153                    channel,
154                    message,
155                })
156            }
157            COPY_DONE_TAG => Message::CopyDone,
158            COMMAND_COMPLETE_TAG => {
159                let tag = buf.read_cstr()?;
160                Message::CommandComplete(CommandCompleteBody { tag })
161            }
162            COPY_DATA_TAG => {
163                let storage = buf.read_all();
164                Message::CopyData(CopyDataBody { storage })
165            }
166            DATA_ROW_TAG => {
167                let len = buf.read_u16::<BigEndian>()?;
168                let storage = buf.read_all();
169                Message::DataRow(DataRowBody { storage, len })
170            }
171            ERROR_RESPONSE_TAG => {
172                let storage = buf.read_all();
173                Message::ErrorResponse(ErrorResponseBody { storage })
174            }
175            COPY_IN_RESPONSE_TAG => {
176                let format = buf.read_u8()?;
177                let len = buf.read_u16::<BigEndian>()?;
178                let storage = buf.read_all();
179                Message::CopyInResponse(CopyInResponseBody {
180                    format,
181                    len,
182                    storage,
183                })
184            }
185            COPY_OUT_RESPONSE_TAG => {
186                let format = buf.read_u8()?;
187                let len = buf.read_u16::<BigEndian>()?;
188                let storage = buf.read_all();
189                Message::CopyOutResponse(CopyOutResponseBody {
190                    format,
191                    len,
192                    storage,
193                })
194            }
195            COPY_BOTH_RESPONSE_TAG => {
196                let format = buf.read_u8()?;
197                let len = buf.read_u16::<BigEndian>()?;
198                let storage = buf.read_all();
199                Message::CopyBothResponse(CopyBothResponseBody {
200                    format,
201                    len,
202                    storage,
203                })
204            }
205            EMPTY_QUERY_RESPONSE_TAG => Message::EmptyQueryResponse,
206            BACKEND_KEY_DATA_TAG => {
207                let process_id = buf.read_i32::<BigEndian>()?;
208                let secret_key = buf.read_i32::<BigEndian>()?;
209                Message::BackendKeyData(BackendKeyDataBody {
210                    process_id,
211                    secret_key,
212                })
213            }
214            NO_DATA_TAG => Message::NoData,
215            NOTICE_RESPONSE_TAG => {
216                let storage = buf.read_all();
217                Message::NoticeResponse(NoticeResponseBody { storage })
218            }
219            AUTHENTICATION_TAG => match buf.read_i32::<BigEndian>()? {
220                0 => Message::AuthenticationOk,
221                2 => Message::AuthenticationKerberosV5,
222                3 => Message::AuthenticationCleartextPassword,
223                5 => {
224                    let mut salt = [0; 4];
225                    buf.read_exact(&mut salt)?;
226                    Message::AuthenticationMd5Password(AuthenticationMd5PasswordBody { salt })
227                }
228                6 => Message::AuthenticationScmCredential,
229                7 => Message::AuthenticationGss,
230                8 => {
231                    let storage = buf.read_all();
232                    Message::AuthenticationGssContinue(AuthenticationGssContinueBody(storage))
233                }
234                9 => Message::AuthenticationSspi,
235                10 => {
236                    let storage = buf.read_all();
237                    Message::AuthenticationSasl(AuthenticationSaslBody(storage))
238                }
239                11 => {
240                    let storage = buf.read_all();
241                    Message::AuthenticationSaslContinue(AuthenticationSaslContinueBody(storage))
242                }
243                12 => {
244                    let storage = buf.read_all();
245                    Message::AuthenticationSaslFinal(AuthenticationSaslFinalBody(storage))
246                }
247                tag => {
248                    return Err(io::Error::new(
249                        io::ErrorKind::InvalidInput,
250                        format!("unknown authentication tag `{}`", tag),
251                    ));
252                }
253            },
254            PORTAL_SUSPENDED_TAG => Message::PortalSuspended,
255            PARAMETER_STATUS_TAG => {
256                let name = buf.read_cstr()?;
257                let value = buf.read_cstr()?;
258                Message::ParameterStatus(ParameterStatusBody { name, value })
259            }
260            PARAMETER_DESCRIPTION_TAG => {
261                let len = buf.read_u16::<BigEndian>()?;
262                let storage = buf.read_all();
263                Message::ParameterDescription(ParameterDescriptionBody { storage, len })
264            }
265            ROW_DESCRIPTION_TAG => {
266                let len = buf.read_u16::<BigEndian>()?;
267                let storage = buf.read_all();
268                Message::RowDescription(RowDescriptionBody { storage, len })
269            }
270            READY_FOR_QUERY_TAG => {
271                let status = buf.read_u8()?;
272                Message::ReadyForQuery(ReadyForQueryBody { status })
273            }
274            tag => {
275                return Err(io::Error::new(
276                    io::ErrorKind::InvalidInput,
277                    format!("unknown message tag `{}`", tag),
278                ));
279            }
280        };
281
282        if !buf.is_empty() {
283            return Err(io::Error::new(
284                io::ErrorKind::InvalidInput,
285                "invalid message length: expected buffer to be empty",
286            ));
287        }
288
289        Ok(Some(message))
290    }
291}
292
293struct Buffer {
294    bytes: Bytes,
295    idx: usize,
296}
297
298impl Buffer {
299    #[inline]
300    fn slice(&self) -> &[u8] {
301        &self.bytes[self.idx..]
302    }
303
304    #[inline]
305    fn is_empty(&self) -> bool {
306        self.slice().is_empty()
307    }
308
309    #[inline]
310    fn read_cstr(&mut self) -> io::Result<Bytes> {
311        match memchr(0, self.slice()) {
312            Some(pos) => {
313                let start = self.idx;
314                let end = start + pos;
315                let cstr = self.bytes.slice(start..end);
316                self.idx = end + 1;
317                Ok(cstr)
318            }
319            None => Err(io::Error::new(
320                io::ErrorKind::UnexpectedEof,
321                "unexpected EOF",
322            )),
323        }
324    }
325
326    #[inline]
327    fn read_all(&mut self) -> Bytes {
328        let buf = self.bytes.slice(self.idx..);
329        self.idx = self.bytes.len();
330        buf
331    }
332}
333
334impl Read for Buffer {
335    #[inline]
336    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
337        let len = {
338            let slice = self.slice();
339            let len = cmp::min(slice.len(), buf.len());
340            buf[..len].copy_from_slice(&slice[..len]);
341            len
342        };
343        self.idx += len;
344        Ok(len)
345    }
346}
347
348pub struct AuthenticationMd5PasswordBody {
349    salt: [u8; 4],
350}
351
352impl AuthenticationMd5PasswordBody {
353    #[inline]
354    pub fn salt(&self) -> [u8; 4] {
355        self.salt
356    }
357}
358
359pub struct AuthenticationGssContinueBody(Bytes);
360
361impl AuthenticationGssContinueBody {
362    #[inline]
363    pub fn data(&self) -> &[u8] {
364        &self.0
365    }
366}
367
368pub struct AuthenticationSaslBody(Bytes);
369
370impl AuthenticationSaslBody {
371    #[inline]
372    pub fn mechanisms(&self) -> SaslMechanisms<'_> {
373        SaslMechanisms(&self.0)
374    }
375}
376
377pub struct SaslMechanisms<'a>(&'a [u8]);
378
379impl<'a> FallibleIterator for SaslMechanisms<'a> {
380    type Item = &'a str;
381    type Error = io::Error;
382
383    #[inline]
384    fn next(&mut self) -> io::Result<Option<&'a str>> {
385        let value_end = find_null(self.0, 0)?;
386        if value_end == 0 {
387            if self.0.len() != 1 {
388                return Err(io::Error::new(
389                    io::ErrorKind::InvalidData,
390                    "invalid message length: expected to be at end of iterator for sasl",
391                ));
392            }
393            Ok(None)
394        } else {
395            let value = get_str(&self.0[..value_end])?;
396            self.0 = &self.0[value_end + 1..];
397            Ok(Some(value))
398        }
399    }
400}
401
402pub struct AuthenticationSaslContinueBody(Bytes);
403
404impl AuthenticationSaslContinueBody {
405    #[inline]
406    pub fn data(&self) -> &[u8] {
407        &self.0
408    }
409}
410
411pub struct AuthenticationSaslFinalBody(Bytes);
412
413impl AuthenticationSaslFinalBody {
414    #[inline]
415    pub fn data(&self) -> &[u8] {
416        &self.0
417    }
418}
419
420pub struct BackendKeyDataBody {
421    process_id: i32,
422    secret_key: i32,
423}
424
425impl BackendKeyDataBody {
426    #[inline]
427    pub fn process_id(&self) -> i32 {
428        self.process_id
429    }
430
431    #[inline]
432    pub fn secret_key(&self) -> i32 {
433        self.secret_key
434    }
435}
436
437pub struct CommandCompleteBody {
438    tag: Bytes,
439}
440
441impl CommandCompleteBody {
442    #[inline]
443    pub fn tag(&self) -> io::Result<&str> {
444        get_str(&self.tag)
445    }
446}
447
448pub struct CopyDataBody {
449    storage: Bytes,
450}
451
452impl CopyDataBody {
453    #[inline]
454    pub fn data(&self) -> &[u8] {
455        &self.storage
456    }
457
458    #[inline]
459    pub fn into_bytes(self) -> Bytes {
460        self.storage
461    }
462}
463
464pub struct CopyInResponseBody {
465    format: u8,
466    len: u16,
467    storage: Bytes,
468}
469
470impl CopyInResponseBody {
471    #[inline]
472    pub fn format(&self) -> u8 {
473        self.format
474    }
475
476    #[inline]
477    pub fn column_formats(&self) -> ColumnFormats<'_> {
478        ColumnFormats {
479            remaining: self.len,
480            buf: &self.storage,
481        }
482    }
483}
484
485pub struct ColumnFormats<'a> {
486    buf: &'a [u8],
487    remaining: u16,
488}
489
490impl<'a> FallibleIterator for ColumnFormats<'a> {
491    type Item = u16;
492    type Error = io::Error;
493
494    #[inline]
495    fn next(&mut self) -> io::Result<Option<u16>> {
496        if self.remaining == 0 {
497            if self.buf.is_empty() {
498                return Ok(None);
499            } else {
500                return Err(io::Error::new(
501                    io::ErrorKind::InvalidInput,
502                    "invalid message length: wrong column formats",
503                ));
504            }
505        }
506
507        self.remaining -= 1;
508        self.buf.read_u16::<BigEndian>().map(Some)
509    }
510
511    #[inline]
512    fn size_hint(&self) -> (usize, Option<usize>) {
513        let len = self.remaining as usize;
514        (len, Some(len))
515    }
516}
517
518pub struct CopyOutResponseBody {
519    format: u8,
520    len: u16,
521    storage: Bytes,
522}
523
524impl CopyOutResponseBody {
525    #[inline]
526    pub fn format(&self) -> u8 {
527        self.format
528    }
529
530    #[inline]
531    pub fn column_formats(&self) -> ColumnFormats<'_> {
532        ColumnFormats {
533            remaining: self.len,
534            buf: &self.storage,
535        }
536    }
537}
538
539#[derive(Debug, Clone)]
540pub struct CopyBothResponseBody {
541    format: u8,
542    len: u16,
543    storage: Bytes,
544}
545
546impl CopyBothResponseBody {
547    #[inline]
548    pub fn format(&self) -> u8 {
549        self.format
550    }
551
552    #[inline]
553    pub fn column_formats(&self) -> ColumnFormats<'_> {
554        ColumnFormats {
555            remaining: self.len,
556            buf: &self.storage,
557        }
558    }
559}
560
561#[derive(Debug, Clone)]
562pub struct DataRowBody {
563    storage: Bytes,
564    len: u16,
565}
566
567impl DataRowBody {
568    #[inline]
569    pub fn ranges(&self) -> DataRowRanges<'_> {
570        DataRowRanges {
571            buf: &self.storage,
572            len: self.storage.len(),
573            remaining: self.len,
574        }
575    }
576
577    #[inline]
578    pub fn buffer(&self) -> &[u8] {
579        &self.storage
580    }
581
582    #[inline]
583    pub fn buffer_bytes(&self) -> &Bytes {
584        &self.storage
585    }
586}
587
588pub struct DataRowRanges<'a> {
589    buf: &'a [u8],
590    len: usize,
591    remaining: u16,
592}
593
594impl<'a> FallibleIterator for DataRowRanges<'a> {
595    type Item = Option<Range<usize>>;
596    type Error = io::Error;
597
598    #[inline]
599    fn next(&mut self) -> io::Result<Option<Option<Range<usize>>>> {
600        if self.remaining == 0 {
601            if self.buf.is_empty() {
602                return Ok(None);
603            } else {
604                return Err(io::Error::new(
605                    io::ErrorKind::InvalidInput,
606                    "invalid message length: datarowrange is not empty",
607                ));
608            }
609        }
610
611        self.remaining -= 1;
612        let len = self.buf.read_i32::<BigEndian>()?;
613        if len < 0 {
614            Ok(Some(None))
615        } else {
616            let len = len as usize;
617            if self.buf.len() < len {
618                return Err(io::Error::new(
619                    io::ErrorKind::UnexpectedEof,
620                    "unexpected EOF",
621                ));
622            }
623            let base = self.len - self.buf.len();
624            self.buf = &self.buf[len..];
625            Ok(Some(Some(base..base + len)))
626        }
627    }
628
629    #[inline]
630    fn size_hint(&self) -> (usize, Option<usize>) {
631        let len = self.remaining as usize;
632        (len, Some(len))
633    }
634}
635
636pub struct ErrorResponseBody {
637    storage: Bytes,
638}
639
640impl ErrorResponseBody {
641    #[inline]
642    pub fn fields(&self) -> ErrorFields<'_> {
643        ErrorFields { buf: &self.storage }
644    }
645}
646
647pub struct ErrorFields<'a> {
648    buf: &'a [u8],
649}
650
651impl<'a> FallibleIterator for ErrorFields<'a> {
652    type Item = ErrorField<'a>;
653    type Error = io::Error;
654
655    #[inline]
656    fn next(&mut self) -> io::Result<Option<ErrorField<'a>>> {
657        let type_ = self.buf.read_u8()?;
658        if type_ == 0 {
659            if self.buf.is_empty() {
660                return Ok(None);
661            } else {
662                return Err(io::Error::new(
663                    io::ErrorKind::InvalidInput,
664                    "invalid message length: error fields is not drained",
665                ));
666            }
667        }
668
669        let value_end = find_null(self.buf, 0)?;
670        let value = &self.buf[..value_end];
671        self.buf = &self.buf[value_end + 1..];
672
673        Ok(Some(ErrorField { type_, value }))
674    }
675}
676
677pub struct ErrorField<'a> {
678    type_: u8,
679    value: &'a [u8],
680}
681
682impl<'a> ErrorField<'a> {
683    #[inline]
684    pub fn type_(&self) -> u8 {
685        self.type_
686    }
687
688    #[inline]
689    #[deprecated(note = "use value_bytes instead", since = "0.6.7")]
690    pub fn value(&self) -> &str {
691        str::from_utf8(self.value).expect("error field value contained non-UTF8 bytes")
692    }
693
694    #[inline]
695    pub fn value_bytes(&self) -> &[u8] {
696        self.value
697    }
698}
699
700pub struct NoticeResponseBody {
701    storage: Bytes,
702}
703
704impl NoticeResponseBody {
705    #[inline]
706    pub fn fields(&self) -> ErrorFields<'_> {
707        ErrorFields { buf: &self.storage }
708    }
709}
710
711pub struct NotificationResponseBody {
712    process_id: i32,
713    channel: Bytes,
714    message: Bytes,
715}
716
717impl NotificationResponseBody {
718    #[inline]
719    pub fn process_id(&self) -> i32 {
720        self.process_id
721    }
722
723    #[inline]
724    pub fn channel(&self) -> io::Result<&str> {
725        get_str(&self.channel)
726    }
727
728    #[inline]
729    pub fn message(&self) -> io::Result<&str> {
730        get_str(&self.message)
731    }
732}
733
734pub struct ParameterDescriptionBody {
735    storage: Bytes,
736    len: u16,
737}
738
739impl ParameterDescriptionBody {
740    #[inline]
741    pub fn parameters(&self) -> Parameters<'_> {
742        Parameters {
743            buf: &self.storage,
744            remaining: self.len,
745        }
746    }
747}
748
749pub struct Parameters<'a> {
750    buf: &'a [u8],
751    remaining: u16,
752}
753
754impl<'a> FallibleIterator for Parameters<'a> {
755    type Item = Oid;
756    type Error = io::Error;
757
758    #[inline]
759    fn next(&mut self) -> io::Result<Option<Oid>> {
760        if self.remaining == 0 {
761            if self.buf.is_empty() {
762                return Ok(None);
763            } else {
764                return Err(io::Error::new(
765                    io::ErrorKind::InvalidInput,
766                    "invalid message length: parameters is not drained",
767                ));
768            }
769        }
770
771        self.remaining -= 1;
772        self.buf.read_u32::<BigEndian>().map(Some)
773    }
774
775    #[inline]
776    fn size_hint(&self) -> (usize, Option<usize>) {
777        let len = self.remaining as usize;
778        (len, Some(len))
779    }
780}
781
782pub struct ParameterStatusBody {
783    name: Bytes,
784    value: Bytes,
785}
786
787impl ParameterStatusBody {
788    #[inline]
789    pub fn name(&self) -> io::Result<&str> {
790        get_str(&self.name)
791    }
792
793    #[inline]
794    pub fn value(&self) -> io::Result<&str> {
795        get_str(&self.value)
796    }
797}
798
799pub struct ReadyForQueryBody {
800    status: u8,
801}
802
803impl ReadyForQueryBody {
804    #[inline]
805    pub fn status(&self) -> u8 {
806        self.status
807    }
808}
809
810pub struct RowDescriptionBody {
811    storage: Bytes,
812    len: u16,
813}
814
815impl RowDescriptionBody {
816    #[inline]
817    pub fn fields(&self) -> Fields<'_> {
818        Fields {
819            buf: &self.storage,
820            remaining: self.len,
821        }
822    }
823}
824
825pub struct Fields<'a> {
826    buf: &'a [u8],
827    remaining: u16,
828}
829
830impl<'a> FallibleIterator for Fields<'a> {
831    type Item = Field<'a>;
832    type Error = io::Error;
833
834    #[inline]
835    fn next(&mut self) -> io::Result<Option<Field<'a>>> {
836        if self.remaining == 0 {
837            if self.buf.is_empty() {
838                return Ok(None);
839            } else {
840                return Err(io::Error::new(
841                    io::ErrorKind::InvalidInput,
842                    "invalid message length: field is not drained",
843                ));
844            }
845        }
846
847        self.remaining -= 1;
848        let name_end = find_null(self.buf, 0)?;
849        let name = get_str(&self.buf[..name_end])?;
850        self.buf = &self.buf[name_end + 1..];
851        let table_oid = self.buf.read_u32::<BigEndian>()?;
852        let column_id = self.buf.read_i16::<BigEndian>()?;
853        let type_oid = self.buf.read_u32::<BigEndian>()?;
854        let type_size = self.buf.read_i16::<BigEndian>()?;
855        let type_modifier = self.buf.read_i32::<BigEndian>()?;
856        let format = self.buf.read_i16::<BigEndian>()?;
857
858        Ok(Some(Field {
859            name,
860            table_oid,
861            column_id,
862            type_oid,
863            type_size,
864            type_modifier,
865            format,
866        }))
867    }
868}
869
870pub struct Field<'a> {
871    name: &'a str,
872    table_oid: Oid,
873    column_id: i16,
874    type_oid: Oid,
875    type_size: i16,
876    type_modifier: i32,
877    format: i16,
878}
879
880impl<'a> Field<'a> {
881    #[inline]
882    pub fn name(&self) -> &'a str {
883        self.name
884    }
885
886    #[inline]
887    pub fn table_oid(&self) -> Oid {
888        self.table_oid
889    }
890
891    #[inline]
892    pub fn column_id(&self) -> i16 {
893        self.column_id
894    }
895
896    #[inline]
897    pub fn type_oid(&self) -> Oid {
898        self.type_oid
899    }
900
901    #[inline]
902    pub fn type_size(&self) -> i16 {
903        self.type_size
904    }
905
906    #[inline]
907    pub fn type_modifier(&self) -> i32 {
908        self.type_modifier
909    }
910
911    #[inline]
912    pub fn format(&self) -> i16 {
913        self.format
914    }
915}
916
917#[inline]
918fn find_null(buf: &[u8], start: usize) -> io::Result<usize> {
919    match memchr(0, &buf[start..]) {
920        Some(pos) => Ok(pos + start),
921        None => Err(io::Error::new(
922            io::ErrorKind::UnexpectedEof,
923            "unexpected EOF",
924        )),
925    }
926}
927
928#[inline]
929fn get_str(buf: &[u8]) -> io::Result<&str> {
930    str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
931}