Skip to content

Commit

Permalink
postgres: tweak DataRow::read
Browse files Browse the repository at this point in the history
mehcode committed Mar 31, 2020

Verified

This commit was signed with the committer’s verified signature.
frostming Frost Ming
1 parent 9be0401 commit bbbc181
Showing 5 changed files with 48 additions and 24 deletions.
2 changes: 2 additions & 0 deletions sqlx-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -29,6 +29,8 @@ sqlite = [ "libsqlite3-sys" ]
tls = [ "async-native-tls" ]
runtime-async-std = [ "async-native-tls/runtime-async-std", "async-std" ]
runtime-tokio = [ "async-native-tls/runtime-tokio", "tokio" ]
# intended for internal benchmarking, do not use
bench = []

[dependencies]
async-native-tls = { version = "0.3.2", default-features = false, optional = true }
8 changes: 4 additions & 4 deletions sqlx-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -7,8 +7,12 @@
#![cfg_attr(not(feature = "sqlite"), forbid(unsafe_code))]
#![recursion_limit = "512"]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(all(test, feature = "bench"), feature(test))]
// #![warn(missing_docs)]

#[cfg(all(test, feature = "bench"))]
extern crate test;

// HACK: Allow a feature name the same name as a dependency
#[cfg(feature = "bigdecimal")]
extern crate bigdecimal_ as bigdecimal;
@@ -65,7 +69,3 @@ pub mod postgres;
pub mod sqlite;

pub use error::{Error, Result};

// Named Lifetimes:
// 'c: connection
// 'q: query string (and arguments)
2 changes: 1 addition & 1 deletion sqlx-core/src/postgres/connection.rs
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ pub struct PgConnection {

// Work buffer for the value ranges of the current row
// This is used as the backing memory for each Row's value indexes
pub(super) current_row_values: Vec<Option<Range<u32>>>,
pub(super) current_row_values: Vec<Option<(u32, u32)>>,

// TODO: Find a use for these values. Perhaps in a debug impl of PgConnection?
#[allow(dead_code)]
58 changes: 40 additions & 18 deletions sqlx-core/src/postgres/protocol/data_row.rs
Original file line number Diff line number Diff line change
@@ -4,58 +4,80 @@ use byteorder::NetworkEndian;
use std::ops::Range;

pub(crate) struct DataRow<'c> {
len: u16,
values: &'c [Option<(u32, u32)>],
buffer: &'c [u8],
values: &'c [Option<Range<u32>>],
}

impl<'c> DataRow<'c> {
pub(crate) fn len(&self) -> usize {
self.len as usize
self.values.len()
}

pub(crate) fn get(&self, index: usize) -> Option<&'c [u8]> {
let range = self.values[index].as_ref()?;

Some(&self.buffer[(range.start as usize)..(range.end as usize)])
self.values[index]
.as_ref()
.map(|(offset, size)| &self.buffer[(*offset as usize)..((*offset + *size) as usize)])
}
}

impl<'c> DataRow<'c> {
pub(crate) fn read(
buffer: &'c [u8],
values: &'c mut Vec<Option<Range<u32>>>,
values: &'c mut Vec<Option<(u32, u32)>>,
) -> crate::Result<Self> {
values.clear();

let mut buf = buffer;

let len = buf.get_u16::<NetworkEndian>()?;

let mut index = 6;
let mut offset = 6;

while values.len() < (len as usize) {
// The length of the column value, in bytes (this count does not include itself).
// Can be zero. As a special case, -1 indicates a NULL column value.
// No value bytes follow in the NULL case.
let size = buf.get_i32::<NetworkEndian>()?;
let mut size = buf.get_i32::<NetworkEndian>()?;

if size == -1 {
if size < 0 {
values.push(None);

index += 4;
offset += 4;
} else {
values.push(Some((index)..(index + (size as u32))));
values.push(Some((offset, size as u32)));

index += (size as u32) + 4;
offset += (size as u32) + 4;
buf.advance(size as usize);
}
}

Ok(Self {
len,
buffer,
values,
})
Ok(Self { buffer, values })
}
}

#[cfg(feature = "bench")]
#[bench]
fn bench_get_data_row(b: &mut test::Bencher) {
let buffer = 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";
let mut values = Vec::with_capacity(10);
let row = DataRow::read(buffer, &mut values).unwrap();

b.iter(|| {
assert_eq!(row.get(0), None);
assert_eq!(row.get(1), Some(&[0, 0, 0, 10][..]));
assert_eq!(row.get(2), None);
assert_eq!(row.get(3), Some(&[0, 0, 0, 20][..]));
assert_eq!(row.get(4), None);
});
}

#[cfg(feature = "bench")]
#[bench]
fn bench_read_data_row(b: &mut test::Bencher) {
let buffer = 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";
let mut values = Vec::with_capacity(10);

b.iter(|| {
let row = DataRow::read(buffer, &mut values).unwrap();
});
}
2 changes: 1 addition & 1 deletion sqlx-core/src/postgres/types/raw/array.rs
Original file line number Diff line number Diff line change
@@ -176,7 +176,7 @@ where
mod tests {
use super::PgArrayDecoder;
use super::PgArrayEncoder;
use crate::postgres::{PgRawBuffer, PgValue, Postgres};
use crate::postgres::{PgRawBuffer, PgValue};

const BUF_BINARY_I32: &[u8] = b"\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x04";

0 comments on commit bbbc181

Please sign in to comment.