sqlx_core/postgres/message/
data_row.rs

1use std::ops::Range;
2
3use byteorder::{BigEndian, ByteOrder};
4use bytes::Bytes;
5
6use crate::error::Error;
7use crate::io::Decode;
8
9/// A row of data from the database.
10#[derive(Debug)]
11pub struct DataRow {
12    pub(crate) storage: Bytes,
13
14    /// Ranges into the stored row data.
15    /// This uses `u32` instead of usize to reduce the size of this type. Values cannot be larger
16    /// than `i32` in postgres.
17    pub(crate) values: Vec<Option<Range<u32>>>,
18}
19
20impl DataRow {
21    #[inline]
22    pub(crate) fn get(&self, index: usize) -> Option<&'_ [u8]> {
23        self.values[index]
24            .as_ref()
25            .map(|col| &self.storage[(col.start as usize)..(col.end as usize)])
26    }
27}
28
29impl Decode<'_> for DataRow {
30    fn decode_with(buf: Bytes, _: ()) -> Result<Self, Error> {
31        let cnt = BigEndian::read_u16(&buf) as usize;
32
33        let mut values = Vec::with_capacity(cnt);
34        let mut offset = 2;
35
36        for _ in 0..cnt {
37            // Length of the column value, in bytes (this count does not include itself).
38            // Can be zero. As a special case, -1 indicates a NULL column value.
39            // No value bytes follow in the NULL case.
40            let length = BigEndian::read_i32(&buf[(offset as usize)..]);
41            offset += 4;
42
43            if length < 0 {
44                values.push(None);
45            } else {
46                values.push(Some(offset..(offset + length as u32)));
47                offset += length as u32;
48            }
49        }
50
51        Ok(Self {
52            storage: buf,
53            values,
54        })
55    }
56}
57
58#[test]
59fn test_decode_data_row() {
60    const DATA: &[u8] = b"\x00\x08\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\n\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00(\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00P";
61
62    let row = DataRow::decode(DATA.into()).unwrap();
63
64    assert_eq!(row.values.len(), 8);
65
66    assert!(row.get(0).is_none());
67    assert_eq!(row.get(1).unwrap(), &[0_u8, 0, 0, 10][..]);
68    assert!(row.get(2).is_none());
69    assert_eq!(row.get(3).unwrap(), &[0_u8, 0, 0, 20][..]);
70    assert!(row.get(4).is_none());
71    assert_eq!(row.get(5).unwrap(), &[0_u8, 0, 0, 40][..]);
72    assert!(row.get(6).is_none());
73    assert_eq!(row.get(7).unwrap(), &[0_u8, 0, 0, 80][..]);
74}
75
76#[cfg(all(test, not(debug_assertions)))]
77#[bench]
78fn bench_data_row_get(b: &mut test::Bencher) {
79    const DATA: &[u8] = b"\x00\x08\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\n\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00(\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00P";
80
81    let row = DataRow::decode(test::black_box(Bytes::from_static(DATA))).unwrap();
82
83    b.iter(|| {
84        let _value = test::black_box(&row).get(3);
85    });
86}
87
88#[cfg(all(test, not(debug_assertions)))]
89#[bench]
90fn bench_decode_data_row(b: &mut test::Bencher) {
91    const DATA: &[u8] = b"\x00\x08\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\n\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00(\xff\xff\xff\xff\x00\x00\x00\x04\x00\x00\x00P";
92
93    b.iter(|| {
94        let _ = DataRow::decode(test::black_box(Bytes::from_static(DATA)));
95    });
96}