Use type conversions from protocol crate
This also changes ToSql and FromSql to explicitly deal in byte buffers.
This commit is contained in:
parent
ff853811cb
commit
f5ec24de78
@ -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" }
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
39
src/lib.rs
39
src/lib.rs
@ -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_));
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
349
src/types/mod.rs
349
src/types/mod.rs
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user