Use type conversions from protocol crate

This also changes ToSql and FromSql to explicitly deal in byte buffers.
This commit is contained in:
Steven Fackler 2016-09-14 23:27:33 -07:00
parent ff853811cb
commit f5ec24de78
16 changed files with 233 additions and 431 deletions

View File

@ -52,3 +52,6 @@ uuid = { version = ">= 0.1, < 0.4", optional = true }
[dev-dependencies]
url = "1.0"
[replace]
"fallible-iterator:0.1.2" = { git = "https://github.com/sfackler/rust-fallible-iterator" }

View File

@ -6,12 +6,12 @@ use std::ascii::AsciiExt;
use std::path::Path;
mod sqlstate;
mod types;
mod type_gen;
fn main() {
let path = Path::new("../src");
sqlstate::build(path);
types::build(path);
type_gen::build(path);
}
fn snake_to_camel(s: &str) -> String {

View File

@ -20,7 +20,7 @@ struct Type {
}
pub fn build(path: &Path) {
let mut file = BufWriter::new(File::create(path.join("types/types.rs")).unwrap());
let mut file = BufWriter::new(File::create(path.join("types/type_gen.rs")).unwrap());
let ranges = parse_ranges();
let types = parse_types(&ranges);

View File

@ -528,7 +528,7 @@ impl InnerConnection {
let mut values = vec![];
for (param, ty) in params.iter().zip(param_types) {
let mut buf = vec![];
match try!(param.to_sql_checked(ty, &mut buf, &SessionInfo::new(self))) {
match try!(param.to_sql_checked(ty, &mut buf, &SessionInfo::new(self)).map_err(Error::Conversion)) {
IsNull::Yes => values.push(None),
IsNull::No => values.push(Some(buf)),
}
@ -671,18 +671,30 @@ impl InnerConnection {
let (name, type_, elem_oid, rngsubtype, basetype, schema, relid) = {
let ctx = SessionInfo::new(self);
let name = try!(String::from_sql(&Type::Name, &mut &**row[0].as_ref().unwrap(), &ctx));
let type_ = try!(i8::from_sql(&Type::Char, &mut &**row[1].as_ref().unwrap(), &ctx));
let elem_oid = try!(Oid::from_sql(&Type::Oid, &mut &**row[2].as_ref().unwrap(), &ctx));
let name = try!(String::from_sql(&Type::Name, &mut &**row[0].as_ref().unwrap(), &ctx)
.map_err(Error::Conversion));
let type_ = try!(i8::from_sql(&Type::Char, &mut &**row[1].as_ref().unwrap(), &ctx)
.map_err(Error::Conversion));
let elem_oid = try!(Oid::from_sql(&Type::Oid, &mut &**row[2].as_ref().unwrap(), &ctx)
.map_err(Error::Conversion));
let rngsubtype = match row[3] {
Some(ref data) => try!(Option::<Oid>::from_sql(&Type::Oid, &mut &**data, &ctx)),
None => try!(Option::<Oid>::from_sql_null(&Type::Oid, &ctx)),
Some(ref data) => {
try!(Option::<Oid>::from_sql(&Type::Oid, &mut &**data, &ctx)
.map_err(Error::Conversion))
},
None => {
try!(Option::<Oid>::from_sql_null(&Type::Oid, &ctx)
.map_err(Error::Conversion))
},
};
let basetype = try!(Oid::from_sql(&Type::Oid, &mut &**row[4].as_ref().unwrap(), &ctx));
let basetype = try!(Oid::from_sql(&Type::Oid, &mut &**row[4].as_ref().unwrap(), &ctx)
.map_err(Error::Conversion));
let schema = try!(String::from_sql(&Type::Name,
&mut &**row[5].as_ref().unwrap(),
&ctx));
let relid = try!(Oid::from_sql(&Type::Oid, &mut &**row[6].as_ref().unwrap(), &ctx));
&ctx)
.map_err(Error::Conversion));
let relid = try!(Oid::from_sql(&Type::Oid, &mut &**row[6].as_ref().unwrap(), &ctx)
.map_err(Error::Conversion));
(name, type_, elem_oid, rngsubtype, basetype, schema, relid)
};
@ -743,7 +755,8 @@ impl InnerConnection {
for row in rows {
variants.push(try!(String::from_sql(&Type::Name,
&mut &**row[0].as_ref().unwrap(),
&ctx)));
&ctx)
.map_err(Error::Conversion)));
}
Ok(variants)
@ -778,8 +791,10 @@ impl InnerConnection {
let ctx = SessionInfo::new(self);
let name = try!(String::from_sql(&Type::Name,
&mut &**row[0].as_ref().unwrap(),
&ctx));
let type_ = try!(Oid::from_sql(&Type::Oid, &mut &**row[1].as_ref().unwrap(), &ctx));
&ctx)
.map_err(Error::Conversion));
let type_ = try!(Oid::from_sql(&Type::Oid, &mut &**row[1].as_ref().unwrap(), &ctx)
.map_err(Error::Conversion));
(name, type_)
};
let type_ = try!(self.get_type(type_));

View File

@ -240,7 +240,7 @@ impl<'a> Row<'a> {
Some(ref data) => FromSql::from_sql(ty, &mut &**data, &SessionInfo::new(&*conn)),
None => FromSql::from_sql_null(ty, &SessionInfo::new(&*conn)),
};
Some(value)
Some(value.map_err(Error::Conversion))
}
/// Retrieves the specified field as a raw buffer of Postgres data.

View File

@ -1,20 +1,16 @@
extern crate bit_vec;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use postgres_protocol::types;
use self::bit_vec::BitVec;
use std::error::Error;
use Result;
use types::{FromSql, ToSql, IsNull, Type, SessionInfo, downcast};
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
impl FromSql for BitVec {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<BitVec> {
let len = try!(raw.read_i32::<BigEndian>()) as usize;
let mut bytes = vec![];
try!(raw.take(((len + 7) / 8) as u64).read_to_end(&mut bytes));
let mut bitvec = BitVec::from_bytes(&bytes);
while bitvec.len() > len {
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<BitVec, Box<Error + Sync + Send>> {
let varbit = try!(types::varbit_from_sql(raw));
let mut bitvec = BitVec::from_bytes(varbit.bytes());
while bitvec.len() > varbit.len() {
bitvec.pop();
}
@ -25,14 +21,8 @@ impl FromSql for BitVec {
}
impl ToSql for BitVec {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut out: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(out.write_i32::<BigEndian>(try!(downcast(self.len()))));
try!(out.write_all(&self.to_bytes()));
fn to_sql(&self, _: &Type, mut out: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
try!(types::varbit_to_sql(self.len(), self.to_bytes().into_iter(), out));
Ok(IsNull::No)
}

View File

@ -1,12 +1,10 @@
extern crate chrono;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use postgres_protocol::types;
use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC, Local,
FixedOffset};
use std::error::Error;
use Result;
use error::Error;
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
fn base() -> NaiveDateTime {
@ -14,8 +12,8 @@ fn base() -> NaiveDateTime {
}
impl FromSql for NaiveDateTime {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<NaiveDateTime> {
let t = try!(raw.read_i64::<BigEndian>());
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<NaiveDateTime, Box<Error + Sync + Send>> {
let t = try!(types::timestamp_from_sql(raw));
Ok(base() + Duration::microseconds(t))
}
@ -23,16 +21,12 @@ impl FromSql for NaiveDateTime {
}
impl ToSql for NaiveDateTime {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let time = match (*self - base()).num_microseconds() {
Some(time) => time,
None => return Err(Error::Conversion("value too large to transmit".into())),
None => return Err("value too large to transmit".into()),
};
try!(w.write_i64::<BigEndian>(time));
types::timestamp_to_sql(time, w);
Ok(IsNull::No)
}
@ -41,7 +35,7 @@ impl ToSql for NaiveDateTime {
}
impl FromSql for DateTime<UTC> {
fn from_sql<R: Read>(type_: &Type, raw: &mut R, info: &SessionInfo) -> Result<DateTime<UTC>> {
fn from_sql(type_: &Type, raw: &[u8], info: &SessionInfo) -> Result<DateTime<UTC>, Box<Error + Sync + Send>> {
let naive = try!(NaiveDateTime::from_sql(type_, raw, info));
Ok(DateTime::from_utc(naive, UTC))
}
@ -50,11 +44,7 @@ impl FromSql for DateTime<UTC> {
}
impl ToSql for DateTime<UTC> {
fn to_sql<W: Write + ?Sized>(&self,
type_: &Type,
mut w: &mut W,
info: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, type_: &Type, w: &mut Vec<u8>, info: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
self.naive_utc().to_sql(type_, w, info)
}
@ -63,7 +53,7 @@ impl ToSql for DateTime<UTC> {
}
impl FromSql for DateTime<Local> {
fn from_sql<R: Read>(type_: &Type, raw: &mut R, info: &SessionInfo) -> Result<DateTime<Local>> {
fn from_sql(type_: &Type, raw: &[u8], info: &SessionInfo) -> Result<DateTime<Local>, Box<Error + Sync + Send>> {
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
Ok(utc.with_timezone(&Local))
}
@ -72,11 +62,7 @@ impl FromSql for DateTime<Local> {
}
impl ToSql for DateTime<Local> {
fn to_sql<W: Write + ?Sized>(&self,
type_: &Type,
mut w: &mut W,
info: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, type_: &Type, mut w: &mut Vec<u8>, info: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
self.with_timezone(&UTC).to_sql(type_, w, info)
}
@ -85,10 +71,7 @@ impl ToSql for DateTime<Local> {
}
impl FromSql for DateTime<FixedOffset> {
fn from_sql<R: Read>(type_: &Type,
raw: &mut R,
info: &SessionInfo)
-> Result<DateTime<FixedOffset>> {
fn from_sql(type_: &Type, raw: &[u8], info: &SessionInfo) -> Result<DateTime<FixedOffset>, Box<Error + Sync + Send>> {
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
Ok(utc.with_timezone(&FixedOffset::east(0)))
}
@ -97,11 +80,7 @@ impl FromSql for DateTime<FixedOffset> {
}
impl ToSql for DateTime<FixedOffset> {
fn to_sql<W: Write + ?Sized>(&self,
type_: &Type,
mut w: &mut W,
info: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, type_: &Type, w: &mut Vec<u8>, info: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
self.with_timezone(&UTC).to_sql(type_, w, info)
}
@ -110,8 +89,8 @@ impl ToSql for DateTime<FixedOffset> {
}
impl FromSql for NaiveDate {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<NaiveDate> {
let jd = try!(raw.read_i32::<BigEndian>());
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<NaiveDate, Box<Error + Sync + Send>> {
let jd = try!(types::date_from_sql(raw));
Ok(base().date() + Duration::days(jd as i64))
}
@ -119,17 +98,13 @@ impl FromSql for NaiveDate {
}
impl ToSql for NaiveDate {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let jd = (*self - base().date()).num_days();
if jd > i32::max_value() as i64 || jd < i32::min_value() as i64 {
return Err(Error::Conversion("value too large to transmit".into()));
return Err("value too large to transmit".into());
}
try!(w.write_i32::<BigEndian>(jd as i32));
types::date_to_sql(jd as i32, w);
Ok(IsNull::No)
}
@ -138,8 +113,8 @@ impl ToSql for NaiveDate {
}
impl FromSql for NaiveTime {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<NaiveTime> {
let usec = try!(raw.read_i64::<BigEndian>());
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<NaiveTime, Box<Error + Sync + Send>> {
let usec = try!(types::time_from_sql(raw));
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(usec))
}
@ -147,17 +122,13 @@ impl FromSql for NaiveTime {
}
impl ToSql for NaiveTime {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let delta = *self - NaiveTime::from_hms(0, 0, 0);
let time = match delta.num_microseconds() {
Some(time) => time,
None => return Err(Error::Conversion("value too large to transmit".into())),
None => return Err("value too large to transmit".into()),
};
try!(w.write_i64::<BigEndian>(time));
types::time_to_sql(time, w);
Ok(IsNull::No)
}

View File

@ -1,16 +1,14 @@
extern crate eui48;
use std::io::prelude::*;
use self::eui48::MacAddress;
use std::error::Error;
use postgres_protocol::types;
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
use Result;
impl FromSql for MacAddress {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<MacAddress> {
let mut bytes = [0; 6];
try!(raw.read_exact(&mut bytes));
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<MacAddress, Box<Error + Sync + Send>> {
let bytes = try!(types::macaddr_from_sql(raw));
Ok(MacAddress::new(bytes))
}
@ -18,8 +16,10 @@ impl FromSql for MacAddress {
}
impl ToSql for MacAddress {
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(self.as_bytes()));
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let mut bytes = [0; 6];
bytes.copy_from_slice(self.as_bytes());
types::macaddr_to_sql(bytes, w);
Ok(IsNull::No)
}

View File

@ -1,19 +1,18 @@
//! Traits dealing with Postgres data types
use fallible_iterator::FallibleIterator;
use postgres_protocol::types::{self, ArrayDimension};
use std::collections::HashMap;
use std::error;
use std::error::Error;
use std::fmt;
use std::io::prelude::*;
use std::sync::Arc;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
#[doc(inline)]
pub use postgres_protocol::message::Oid;
pub use postgres_protocol::Oid;
pub use self::types::Type;
pub use self::type_gen::Type;
pub use self::special::{Date, Timestamp};
use {Result, SessionInfoNew, InnerConnection, OtherNew, WrongTypeNew, FieldNew};
use error::Error;
use {SessionInfoNew, InnerConnection, OtherNew, WrongTypeNew, FieldNew};
/// Generates a simple implementation of `ToSql::accepts` which accepts the
/// types passed to it.
@ -37,9 +36,9 @@ macro_rules! to_sql_checked {
() => {
fn to_sql_checked(&self,
ty: &$crate::types::Type,
out: &mut ::std::io::Write,
out: &mut ::std::vec::Vec<u8>,
ctx: &$crate::types::SessionInfo)
-> $crate::Result<$crate::types::IsNull> {
-> ::std::result::Result<$crate::types::IsNull, Box<::std::error::Error + ::std::marker::Sync + ::std::marker::Send>> {
$crate::types::__to_sql_checked(self, ty, out, ctx)
}
}
@ -48,11 +47,11 @@ macro_rules! to_sql_checked {
// WARNING: this function is not considered part of this crate's public API.
// It is subject to change at any time.
#[doc(hidden)]
pub fn __to_sql_checked<T>(v: &T, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>
pub fn __to_sql_checked<T>(v: &T, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>>
where T: ToSql
{
if !T::accepts(ty) {
return Err(Error::Conversion(Box::new(WrongType(ty.clone()))));
return Err(Box::new(WrongType(ty.clone())));
}
v.to_sql(ty, out, ctx)
}
@ -73,7 +72,7 @@ mod chrono;
mod eui48;
mod special;
mod types;
mod type_gen;
/// A structure providing information for conversion methods.
pub struct SessionInfo<'a> {
@ -214,11 +213,11 @@ pub struct WasNull;
impl fmt::Display for WasNull {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(error::Error::description(self))
fmt.write_str(self.description())
}
}
impl error::Error for WasNull {
impl Error for WasNull {
fn description(&self) -> &str {
"a Postgres value was `NULL`"
}
@ -237,7 +236,7 @@ impl fmt::Display for WrongType {
}
}
impl error::Error for WrongType {
impl Error for WrongType {
fn description(&self) -> &str {
"cannot convert to or from a Postgres value"
}
@ -303,12 +302,12 @@ impl WrongTypeNew for WrongType {
/// `FromSql` is implemented for `Vec<T>` where `T` implements `FromSql`, and
/// corresponds to one-dimensional Postgres arrays.
pub trait FromSql: Sized {
/// Creates a new value of this type from a `Read`er of the binary format
/// of the specified Postgres `Type`.
/// Creates a new value of this type from a buffer of data of the specified
/// Postgres `Type` in its binary format.
///
/// The caller of this method is responsible for ensuring that this type
/// is compatible with the Postgres `Type`.
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self>;
fn from_sql(ty: &Type, raw: &[u8], ctx: &SessionInfo) -> Result<Self, Box<Error + Sync + Send>>;
/// Creates a new value of this type from a `NULL` SQL value.
///
@ -316,10 +315,10 @@ pub trait FromSql: Sized {
/// is compatible with the Postgres `Type`.
///
/// The default implementation returns
/// `Err(Error::Conversion(Box::new(WasNull))`.
/// `Err(Box::new(WasNull))`.
#[allow(unused_variables)]
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self> {
Err(Error::Conversion(Box::new(WasNull)))
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self, Box<Error + Sync + Send>> {
Err(Box::new(WasNull))
}
/// Determines if a value of this type can be created from the specified
@ -328,11 +327,11 @@ pub trait FromSql: Sized {
}
impl<T: FromSql> FromSql for Option<T> {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Option<T>> {
fn from_sql(ty: &Type, raw: &[u8], ctx: &SessionInfo) -> Result<Option<T>, Box<Error + Sync + Send>> {
<T as FromSql>::from_sql(ty, raw, ctx).map(Some)
}
fn from_sql_null(_: &Type, _: &SessionInfo) -> Result<Option<T>> {
fn from_sql_null(_: &Type, _: &SessionInfo) -> Result<Option<T>, Box<Error + Sync + Send>> {
Ok(None)
}
@ -341,49 +340,26 @@ impl<T: FromSql> FromSql for Option<T> {
}
}
impl FromSql for bool {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<bool> {
Ok(try!(raw.read_u8()) != 0)
}
accepts!(Type::Bool);
}
impl<T: FromSql> FromSql for Vec<T> {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, info: &SessionInfo) -> Result<Vec<T>> {
fn from_sql(ty: &Type, raw: &[u8], info: &SessionInfo) -> Result<Vec<T>, Box<Error + Sync + Send>> {
let member_type = match *ty.kind() {
Kind::Array(ref member) => member,
_ => panic!("expected array type"),
};
let dimensions = try!(raw.read_i32::<BigEndian>());
if dimensions > 1 {
return Err(Error::Conversion("array contains too many dimensions".into()));
let array = try!(types::array_from_sql(raw));
if try!(array.dimensions().count()) > 1 {
return Err("array contains too many dimensions".into());
}
let _has_nulls = try!(raw.read_i32::<BigEndian>());
let _member_oid = try!(raw.read_u32::<BigEndian>());
if dimensions == 0 {
return Ok(vec![]);
array.values()
.and_then(|v| {
match v {
Some(v) => T::from_sql(&member_type, v, info),
None => T::from_sql_null(&member_type, info),
}
let count = try!(raw.read_i32::<BigEndian>());
let _index_offset = try!(raw.read_i32::<BigEndian>());
let mut out = Vec::with_capacity(count as usize);
for _ in 0..count {
let len = try!(raw.read_i32::<BigEndian>());
let value = if len < 0 {
try!(T::from_sql_null(&member_type, info))
} else {
let mut raw = raw.take(len as u64);
try!(T::from_sql(&member_type, &mut raw, info))
};
out.push(value)
}
Ok(out)
})
.collect()
}
fn accepts(ty: &Type) -> bool {
@ -395,20 +371,16 @@ impl<T: FromSql> FromSql for Vec<T> {
}
impl FromSql for Vec<u8> {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Vec<u8>> {
let mut buf = vec![];
try!(raw.read_to_end(&mut buf));
Ok(buf)
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<Vec<u8>, Box<Error + Sync + Send>> {
Ok(types::bytea_from_sql(raw).to_owned())
}
accepts!(Type::Bytea);
}
impl FromSql for String {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<String> {
let mut buf = vec![];
try!(raw.read_to_end(&mut buf));
String::from_utf8(buf).map_err(|err| Error::Conversion(Box::new(err)))
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<String, Box<Error + Sync + Send>> {
types::text_from_sql(raw).map(|b| b.to_owned())
}
fn accepts(ty: &Type) -> bool {
@ -420,19 +392,11 @@ impl FromSql for String {
}
}
impl FromSql for i8 {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<i8> {
Ok(try!(raw.read_i8()))
}
accepts!(Type::Char);
}
macro_rules! primitive_from {
macro_rules! simple_from {
($t:ty, $f:ident, $($expected:pat),+) => {
impl FromSql for $t {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<$t> {
Ok(try!(raw.$f::<BigEndian>()))
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<$t, Box<Error + Sync + Send>> {
types::$f(raw)
}
accepts!($($expected),+);
@ -440,47 +404,20 @@ macro_rules! primitive_from {
}
}
primitive_from!(i16, read_i16, Type::Int2);
primitive_from!(i32, read_i32, Type::Int4);
primitive_from!(u32, read_u32, Type::Oid);
primitive_from!(i64, read_i64, Type::Int8);
primitive_from!(f32, read_f32, Type::Float4);
primitive_from!(f64, read_f64, Type::Float8);
simple_from!(bool, bool_from_sql, Type::Bool);
simple_from!(i8, char_from_sql, Type::Char);
simple_from!(i16, int2_from_sql, Type::Int2);
simple_from!(i32, int4_from_sql, Type::Int4);
simple_from!(u32, oid_from_sql, Type::Oid);
simple_from!(i64, int8_from_sql, Type::Int8);
simple_from!(f32, float4_from_sql, Type::Float4);
simple_from!(f64, float8_from_sql, Type::Float8);
impl FromSql for HashMap<String, Option<String>> {
fn from_sql<R: Read>(_: &Type,
raw: &mut R,
_: &SessionInfo)
-> Result<HashMap<String, Option<String>>> {
let mut map = HashMap::new();
let count = try!(raw.read_i32::<BigEndian>());
for _ in 0..count {
let key_len = try!(raw.read_i32::<BigEndian>());
let mut key = vec![0; key_len as usize];
try!(raw.read_exact(&mut key));
let key = match String::from_utf8(key) {
Ok(key) => key,
Err(err) => return Err(Error::Conversion(Box::new(err))),
};
let val_len = try!(raw.read_i32::<BigEndian>());
let val = if val_len < 0 {
None
} else {
let mut val = vec![0; val_len as usize];
try!(raw.read_exact(&mut val));
match String::from_utf8(val) {
Ok(val) => Some(val),
Err(err) => return Err(Error::Conversion(Box::new(err))),
}
};
map.insert(key, val);
}
Ok(map)
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<HashMap<String, Option<String>>, Box<Error + Sync + Send>> {
try!(types::hstore_from_sql(raw))
.map(|(k, v)| (k.to_owned(), v.map(|v| v.to_owned())))
.collect()
}
fn accepts(ty: &Type) -> bool {
@ -556,7 +493,7 @@ pub enum IsNull {
/// 1.
pub trait ToSql: fmt::Debug {
/// Converts the value of `self` into the binary format of the specified
/// Postgres `Type`, writing it to `out`.
/// Postgres `Type`, appending it to `out`.
///
/// The caller of this method is responsible for ensuring that this type
/// is compatible with the Postgres `Type`.
@ -564,9 +501,7 @@ pub trait ToSql: fmt::Debug {
/// The return value indicates if this value should be represented as
/// `NULL`. If this is the case, implementations **must not** write
/// anything to `out`.
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
where Self: Sized,
W: Write;
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> where Self: Sized;
/// Determines if a value of this type can be converted to the specified
/// Postgres `Type`.
@ -576,35 +511,25 @@ pub trait ToSql: fmt::Debug {
///
/// *All* implementations of this method should be generated by the
/// `to_sql_checked!()` macro.
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>;
fn to_sql_checked(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>>;
}
impl<'a, T> ToSql for &'a T
where T: ToSql
{
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
(*self).to_sql(ty, out, ctx)
}
fn accepts(ty: &Type) -> bool {
T::accepts(ty)
}
to_sql_checked!();
}
impl<T: ToSql> ToSql for Option<T> {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
match *self {
Some(ref val) => val.to_sql(ty, out, ctx),
None => Ok(IsNull::Yes),
@ -614,55 +539,35 @@ impl<T: ToSql> ToSql for Option<T> {
fn accepts(ty: &Type) -> bool {
<T as ToSql>::accepts(ty)
}
}
impl ToSql for bool {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_u8(*self as u8));
Ok(IsNull::No)
}
accepts!(Type::Bool);
}
impl<'a, T: ToSql> ToSql for &'a [T] {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
mut w: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let member_type = match *ty.kind() {
Kind::Array(ref member) => member,
_ => panic!("expected array type"),
};
try!(w.write_i32::<BigEndian>(1)); // number of dimensions
try!(w.write_i32::<BigEndian>(1)); // has nulls
try!(w.write_u32::<BigEndian>(member_type.oid()));
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
try!(w.write_i32::<BigEndian>(1)); // index offset
let mut inner_buf = vec![];
for e in *self {
match try!(e.to_sql(&member_type, &mut inner_buf, ctx)) {
IsNull::No => {
try!(w.write_i32::<BigEndian>(try!(downcast(inner_buf.len()))));
try!(w.write_all(&inner_buf));
}
IsNull::Yes => try!(w.write_i32::<BigEndian>(-1)),
}
inner_buf.clear();
let dimensions = [
ArrayDimension {
len: try!(downcast(self.len())),
lower_bound: 1,
}
];
try!(types::array_to_sql(dimensions.iter().cloned(),
true,
member_type.oid(),
self.iter(),
|e, w| {
match try!(e.to_sql(member_type, w, ctx)) {
IsNull::No => Ok(types::IsNull::No),
IsNull::Yes => Ok(types::IsNull::Yes),
}
},
w));
Ok(IsNull::No)
}
@ -672,48 +577,48 @@ impl<'a, T: ToSql> ToSql for &'a [T] {
_ => false,
}
}
to_sql_checked!();
}
impl<'a> ToSql for &'a [u8] {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(*self));
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
types::bytea_to_sql(*self, w);
Ok(IsNull::No)
}
accepts!(Type::Bytea);
to_sql_checked!();
}
impl<T: ToSql> ToSql for Vec<T> {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
<&[T] as ToSql>::to_sql(&&**self, ty, w, ctx)
}
fn accepts(ty: &Type) -> bool {
<&[T] as ToSql>::accepts(ty)
}
to_sql_checked!();
}
impl ToSql for Vec<u8> {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
}
fn accepts(ty: &Type) -> bool {
<&[u8] as ToSql>::accepts(ty)
}
to_sql_checked!();
}
impl<'a> ToSql for &'a str {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(self.as_bytes()));
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
types::text_to_sql(*self, w);
Ok(IsNull::No)
}
@ -724,81 +629,49 @@ impl<'a> ToSql for &'a str {
_ => false,
}
}
to_sql_checked!();
}
impl ToSql for String {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
}
fn accepts(ty: &Type) -> bool {
<&str as ToSql>::accepts(ty)
}
}
impl ToSql for i8 {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_i8(*self));
Ok(IsNull::No)
}
accepts!(Type::Char);
}
macro_rules! to_primitive {
macro_rules! simple_to {
($t:ty, $f:ident, $($expected:pat),+) => {
impl ToSql for $t {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
-> Result<IsNull> {
try!(w.$f::<BigEndian>(*self));
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
types::$f(*self, w);
Ok(IsNull::No)
}
accepts!($($expected),+);
to_sql_checked!();
}
}
}
to_primitive!(i16, write_i16, Type::Int2);
to_primitive!(i32, write_i32, Type::Int4);
to_primitive!(u32, write_u32, Type::Oid);
to_primitive!(i64, write_i64, Type::Int8);
to_primitive!(f32, write_f32, Type::Float4);
to_primitive!(f64, write_f64, Type::Float8);
simple_to!(bool, bool_to_sql, Type::Bool);
simple_to!(i8, char_to_sql, Type::Char);
simple_to!(i16, int2_to_sql, Type::Int2);
simple_to!(i32, int4_to_sql, Type::Int4);
simple_to!(u32, oid_to_sql, Type::Oid);
simple_to!(i64, int8_to_sql, Type::Int8);
simple_to!(f32, float4_to_sql, Type::Float4);
simple_to!(f64, float8_to_sql, Type::Float8);
impl ToSql for HashMap<String, Option<String>> {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
for (key, val) in self {
try!(w.write_i32::<BigEndian>(try!(downcast(key.len()))));
try!(w.write_all(key.as_bytes()));
match *val {
Some(ref val) => {
try!(w.write_i32::<BigEndian>(try!(downcast(val.len()))));
try!(w.write_all(val.as_bytes()));
}
None => try!(w.write_i32::<BigEndian>(-1)),
}
}
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
try!(types::hstore_to_sql(self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))), w));
Ok(IsNull::No)
}
@ -808,11 +681,13 @@ impl ToSql for HashMap<String, Option<String>> {
_ => false,
}
}
to_sql_checked!();
}
fn downcast(len: usize) -> Result<i32> {
fn downcast(len: usize) -> Result<i32, Box<Error + Sync + Send>> {
if len > i32::max_value() as usize {
Err(Error::Conversion("value too large to transmit".into()))
Err("value too large to transmit".into())
} else {
Ok(len as i32)
}

View File

@ -1,39 +1,33 @@
extern crate rustc_serialize;
use self::rustc_serialize::json;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io::{Cursor, Write};
use byteorder::ReadBytesExt;
use std::error::Error;
use Result;
use error::Error;
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
impl FromSql for json::Json {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, _: &SessionInfo) -> Result<json::Json> {
fn from_sql(ty: &Type, raw: &[u8], _: &SessionInfo) -> Result<json::Json, Box<Error + Sync + Send>> {
let mut raw = Cursor::new(raw);
if let Type::Jsonb = *ty {
// We only support version 1 of the jsonb binary format
if try!(raw.read_u8()) != 1 {
return Err(Error::Conversion("unsupported JSONB encoding version".into()));
return Err("unsupported JSONB encoding version".into());
}
}
json::Json::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err)))
json::Json::from_reader(&mut raw).map_err(Into::into)
}
accepts!(Type::Json, Type::Jsonb);
}
impl ToSql for json::Json {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
mut out: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
if let Type::Jsonb = *ty {
try!(out.write_u8(1));
out.push(1);
}
try!(write!(out, "{}", self));
Ok(IsNull::No)
}

View File

@ -1,39 +1,32 @@
extern crate serde_json;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt};
use byteorder::ReadBytesExt;
use self::serde_json::Value;
use std::error::Error;
use std::io::Write;
use Result;
use error::Error;
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
impl FromSql for Value {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, _: &SessionInfo) -> Result<Value> {
fn from_sql(ty: &Type, mut raw: &[u8], _: &SessionInfo) -> Result<Value, Box<Error + Sync + Send>> {
if let Type::Jsonb = *ty {
// We only support version 1 of the jsonb binary format
if try!(raw.read_u8()) != 1 {
return Err(Error::Conversion("unsupported JSONB encoding version".into()));
return Err("unsupported JSONB encoding version".into());
}
}
serde_json::de::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err)))
serde_json::de::from_reader(raw).map_err(Into::into)
}
accepts!(Type::Json, Type::Jsonb);
}
impl ToSql for Value {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
mut out: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
if let Type::Jsonb = *ty {
try!(out.write_u8(1));
out.push(1);
}
try!(write!(out, "{:?}", self));
Ok(IsNull::No)
}

View File

@ -1,10 +1,7 @@
use std::io::prelude::*;
use postgres_protocol::types;
use std::{i32, i64};
use std::error::Error;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use Result;
use error::Error;
use types::{Type, FromSql, ToSql, IsNull, SessionInfo};
/// A wrapper that can be used to represent infinity with `Type::Date` types.
@ -19,18 +16,11 @@ pub enum Date<T> {
}
impl<T: FromSql> FromSql for Date<T> {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self> {
if *ty != Type::Date {
return Err(Error::Conversion("expected date type".into()));
}
let mut buf = [0; 4];
try!(raw.read_exact(buf.as_mut()));
match try!(buf.as_ref().read_i32::<BigEndian>()) {
fn from_sql(ty: &Type, raw: &[u8], ctx: &SessionInfo) -> Result<Self, Box<Error + Sync + Send>> {
match try!(types::date_from_sql(raw)) {
i32::MAX => Ok(Date::PosInfinity),
i32::MIN => Ok(Date::NegInfinity),
_ => T::from_sql(ty, &mut &mut buf.as_ref(), ctx).map(Date::Value),
_ => T::from_sql(ty, raw, ctx).map(Date::Value),
}
}
@ -39,22 +29,14 @@ impl<T: FromSql> FromSql for Date<T> {
}
}
impl<T: ToSql> ToSql for Date<T> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
if *ty != Type::Date {
return Err(Error::Conversion("expected date type".into()));
}
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let value = match *self {
Date::PosInfinity => i32::MAX,
Date::NegInfinity => i32::MIN,
Date::Value(ref v) => return v.to_sql(ty, out, ctx),
};
try!(out.write_i32::<BigEndian>(value));
types::date_to_sql(value, out);
Ok(IsNull::No)
}
@ -78,18 +60,11 @@ pub enum Timestamp<T> {
}
impl<T: FromSql> FromSql for Timestamp<T> {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self> {
if *ty != Type::Timestamp && *ty != Type::Timestamptz {
return Err(Error::Conversion("expected timestamp or timestamptz type".into()));
}
let mut buf = [0; 8];
try!(raw.read_exact(buf.as_mut()));
match try!(buf.as_ref().read_i64::<BigEndian>()) {
fn from_sql(ty: &Type, raw: &[u8], ctx: &SessionInfo) -> Result<Self, Box<Error + Sync + Send>> {
match try!(types::timestamp_from_sql(raw)) {
i64::MAX => Ok(Timestamp::PosInfinity),
i64::MIN => Ok(Timestamp::NegInfinity),
_ => T::from_sql(ty, &mut &mut buf.as_ref(), ctx).map(Timestamp::Value),
_ => T::from_sql(ty, raw, ctx).map(Timestamp::Value),
}
}
@ -99,22 +74,14 @@ impl<T: FromSql> FromSql for Timestamp<T> {
}
impl<T: ToSql> ToSql for Timestamp<T> {
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
if *ty != Type::Timestamp && *ty != Type::Timestamptz {
return Err(Error::Conversion("expected timestamp or timestamptz type".into()));
}
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let value = match *self {
Timestamp::PosInfinity => i64::MAX,
Timestamp::NegInfinity => i64::MIN,
Timestamp::Value(ref v) => return v.to_sql(ty, out, ctx),
};
try!(out.write_i64::<BigEndian>(value));
types::timestamp_to_sql(value, out);
Ok(IsNull::No)
}

View File

@ -1,10 +1,9 @@
extern crate time;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use self::time::Timespec;
use std::io::prelude::*;
use std::error::Error;
use postgres_protocol::types;
use Result;
use types::{Type, FromSql, ToSql, IsNull, SessionInfo};
const USEC_PER_SEC: i64 = 1_000_000;
@ -14,8 +13,8 @@ const NSEC_PER_USEC: i64 = 1_000;
const TIME_SEC_CONVERSION: i64 = 946684800;
impl FromSql for Timespec {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Timespec> {
let t = try!(raw.read_i64::<BigEndian>());
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<Timespec, Box<Error + Sync + Send>> {
let t = try!(types::timestamp_from_sql(raw));
let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION;
let mut usec = t % USEC_PER_SEC;
@ -31,13 +30,9 @@ impl FromSql for Timespec {
}
impl ToSql for Timespec {
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC;
try!(w.write_i64::<BigEndian>(t));
types::timestamp_to_sql(t, w);
Ok(IsNull::No)
}

View File

@ -1,15 +1,14 @@
extern crate uuid;
use std::io::prelude::*;
use postgres_protocol::types;
use self::uuid::Uuid;
use std::error::Error;
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
use Result;
impl FromSql for Uuid {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Uuid> {
let mut bytes = [0; 16];
try!(raw.read_exact(&mut bytes));
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<Uuid, Box<Error + Sync + Send>> {
let bytes = try!(types::uuid_from_sql(raw));
Ok(Uuid::from_bytes(&bytes).unwrap())
}
@ -17,8 +16,8 @@ impl FromSql for Uuid {
}
impl ToSql for Uuid {
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(self.as_bytes()));
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
types::uuid_to_sql(*self.as_bytes(), w);
Ok(IsNull::No)
}

View File

@ -1,8 +1,10 @@
use std::collections::HashMap;
use std::error;
use std::f32;
use std::f64;
use std::fmt;
use std::io::{Read, Write};
use std::result;
use postgres::{Connection, TlsMode, Result};
use postgres::error::Error;
@ -251,9 +253,7 @@ fn domain() {
struct SessionId(Vec<u8>);
impl ToSql for SessionId {
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
where W: Write
{
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> result::Result<IsNull, Box<error::Error + Sync + Send>> {
let inner = match *ty.kind() {
Kind::Domain(ref inner) => inner,
_ => unreachable!(),
@ -269,7 +269,7 @@ fn domain() {
}
impl FromSql for SessionId {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self> {
fn from_sql(ty: &Type, raw: &[u8], ctx: &SessionInfo) -> result::Result<Self, Box<error::Error + Sync + Send>> {
Vec::<u8>::from_sql(ty, raw, ctx).map(SessionId)
}