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