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#[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}