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