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