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