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]
|
[dev-dependencies]
|
||||||
url = "1.0"
|
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;
|
use std::path::Path;
|
||||||
|
|
||||||
mod sqlstate;
|
mod sqlstate;
|
||||||
mod types;
|
mod type_gen;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let path = Path::new("../src");
|
let path = Path::new("../src");
|
||||||
sqlstate::build(path);
|
sqlstate::build(path);
|
||||||
types::build(path);
|
type_gen::build(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snake_to_camel(s: &str) -> String {
|
fn snake_to_camel(s: &str) -> String {
|
||||||
|
@ -20,7 +20,7 @@ struct Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(path: &Path) {
|
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 ranges = parse_ranges();
|
||||||
let types = parse_types(&ranges);
|
let types = parse_types(&ranges);
|
39
src/lib.rs
39
src/lib.rs
@ -528,7 +528,7 @@ impl InnerConnection {
|
|||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
for (param, ty) in params.iter().zip(param_types) {
|
for (param, ty) in params.iter().zip(param_types) {
|
||||||
let mut buf = vec![];
|
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::Yes => values.push(None),
|
||||||
IsNull::No => values.push(Some(buf)),
|
IsNull::No => values.push(Some(buf)),
|
||||||
}
|
}
|
||||||
@ -671,18 +671,30 @@ impl InnerConnection {
|
|||||||
|
|
||||||
let (name, type_, elem_oid, rngsubtype, basetype, schema, relid) = {
|
let (name, type_, elem_oid, rngsubtype, basetype, schema, relid) = {
|
||||||
let ctx = SessionInfo::new(self);
|
let ctx = SessionInfo::new(self);
|
||||||
let name = try!(String::from_sql(&Type::Name, &mut &**row[0].as_ref().unwrap(), &ctx));
|
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));
|
.map_err(Error::Conversion));
|
||||||
let elem_oid = try!(Oid::from_sql(&Type::Oid, &mut &**row[2].as_ref().unwrap(), &ctx));
|
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] {
|
let rngsubtype = match row[3] {
|
||||||
Some(ref data) => try!(Option::<Oid>::from_sql(&Type::Oid, &mut &**data, &ctx)),
|
Some(ref data) => {
|
||||||
None => try!(Option::<Oid>::from_sql_null(&Type::Oid, &ctx)),
|
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,
|
let schema = try!(String::from_sql(&Type::Name,
|
||||||
&mut &**row[5].as_ref().unwrap(),
|
&mut &**row[5].as_ref().unwrap(),
|
||||||
&ctx));
|
&ctx)
|
||||||
let relid = try!(Oid::from_sql(&Type::Oid, &mut &**row[6].as_ref().unwrap(), &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)
|
(name, type_, elem_oid, rngsubtype, basetype, schema, relid)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -743,7 +755,8 @@ impl InnerConnection {
|
|||||||
for row in rows {
|
for row in rows {
|
||||||
variants.push(try!(String::from_sql(&Type::Name,
|
variants.push(try!(String::from_sql(&Type::Name,
|
||||||
&mut &**row[0].as_ref().unwrap(),
|
&mut &**row[0].as_ref().unwrap(),
|
||||||
&ctx)));
|
&ctx)
|
||||||
|
.map_err(Error::Conversion)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(variants)
|
Ok(variants)
|
||||||
@ -778,8 +791,10 @@ impl InnerConnection {
|
|||||||
let ctx = SessionInfo::new(self);
|
let ctx = SessionInfo::new(self);
|
||||||
let name = try!(String::from_sql(&Type::Name,
|
let name = try!(String::from_sql(&Type::Name,
|
||||||
&mut &**row[0].as_ref().unwrap(),
|
&mut &**row[0].as_ref().unwrap(),
|
||||||
&ctx));
|
&ctx)
|
||||||
let type_ = try!(Oid::from_sql(&Type::Oid, &mut &**row[1].as_ref().unwrap(), &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_)
|
(name, type_)
|
||||||
};
|
};
|
||||||
let type_ = try!(self.get_type(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)),
|
Some(ref data) => FromSql::from_sql(ty, &mut &**data, &SessionInfo::new(&*conn)),
|
||||||
None => FromSql::from_sql_null(ty, &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.
|
/// Retrieves the specified field as a raw buffer of Postgres data.
|
||||||
|
@ -1,20 +1,16 @@
|
|||||||
extern crate bit_vec;
|
extern crate bit_vec;
|
||||||
|
|
||||||
use std::io::prelude::*;
|
use postgres_protocol::types;
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
|
||||||
use self::bit_vec::BitVec;
|
use self::bit_vec::BitVec;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
use Result;
|
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
|
||||||
use types::{FromSql, ToSql, IsNull, Type, SessionInfo, downcast};
|
|
||||||
|
|
||||||
impl FromSql for BitVec {
|
impl FromSql for BitVec {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<BitVec> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<BitVec, Box<Error + Sync + Send>> {
|
||||||
let len = try!(raw.read_i32::<BigEndian>()) as usize;
|
let varbit = try!(types::varbit_from_sql(raw));
|
||||||
let mut bytes = vec![];
|
let mut bitvec = BitVec::from_bytes(varbit.bytes());
|
||||||
try!(raw.take(((len + 7) / 8) as u64).read_to_end(&mut bytes));
|
while bitvec.len() > varbit.len() {
|
||||||
|
|
||||||
let mut bitvec = BitVec::from_bytes(&bytes);
|
|
||||||
while bitvec.len() > len {
|
|
||||||
bitvec.pop();
|
bitvec.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,14 +21,8 @@ impl FromSql for BitVec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for BitVec {
|
impl ToSql for BitVec {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, _: &Type, mut out: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
_: &Type,
|
try!(types::varbit_to_sql(self.len(), self.to_bytes().into_iter(), out));
|
||||||
mut out: &mut W,
|
|
||||||
_: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
try!(out.write_i32::<BigEndian>(try!(downcast(self.len()))));
|
|
||||||
try!(out.write_all(&self.to_bytes()));
|
|
||||||
|
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
|
|
||||||
use std::io::prelude::*;
|
use postgres_protocol::types;
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
|
||||||
use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC, Local,
|
use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC, Local,
|
||||||
FixedOffset};
|
FixedOffset};
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
use Result;
|
|
||||||
use error::Error;
|
|
||||||
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
|
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
|
||||||
|
|
||||||
fn base() -> NaiveDateTime {
|
fn base() -> NaiveDateTime {
|
||||||
@ -14,8 +12,8 @@ fn base() -> NaiveDateTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for NaiveDateTime {
|
impl FromSql for NaiveDateTime {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<NaiveDateTime> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<NaiveDateTime, Box<Error + Sync + Send>> {
|
||||||
let t = try!(raw.read_i64::<BigEndian>());
|
let t = try!(types::timestamp_from_sql(raw));
|
||||||
Ok(base() + Duration::microseconds(t))
|
Ok(base() + Duration::microseconds(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,16 +21,12 @@ impl FromSql for NaiveDateTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for NaiveDateTime {
|
impl ToSql for NaiveDateTime {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
_: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
_: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
let time = match (*self - base()).num_microseconds() {
|
let time = match (*self - base()).num_microseconds() {
|
||||||
Some(time) => time,
|
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)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +35,7 @@ impl ToSql for NaiveDateTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for DateTime<UTC> {
|
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));
|
let naive = try!(NaiveDateTime::from_sql(type_, raw, info));
|
||||||
Ok(DateTime::from_utc(naive, UTC))
|
Ok(DateTime::from_utc(naive, UTC))
|
||||||
}
|
}
|
||||||
@ -50,11 +44,7 @@ impl FromSql for DateTime<UTC> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for DateTime<UTC> {
|
impl ToSql for DateTime<UTC> {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, type_: &Type, w: &mut Vec<u8>, info: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
type_: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
info: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
self.naive_utc().to_sql(type_, w, info)
|
self.naive_utc().to_sql(type_, w, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +53,7 @@ impl ToSql for DateTime<UTC> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for DateTime<Local> {
|
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));
|
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
|
||||||
Ok(utc.with_timezone(&Local))
|
Ok(utc.with_timezone(&Local))
|
||||||
}
|
}
|
||||||
@ -72,11 +62,7 @@ impl FromSql for DateTime<Local> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for DateTime<Local> {
|
impl ToSql for DateTime<Local> {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, type_: &Type, mut w: &mut Vec<u8>, info: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
type_: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
info: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
self.with_timezone(&UTC).to_sql(type_, w, info)
|
self.with_timezone(&UTC).to_sql(type_, w, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,10 +71,7 @@ impl ToSql for DateTime<Local> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for DateTime<FixedOffset> {
|
impl FromSql for DateTime<FixedOffset> {
|
||||||
fn from_sql<R: Read>(type_: &Type,
|
fn from_sql(type_: &Type, raw: &[u8], info: &SessionInfo) -> Result<DateTime<FixedOffset>, Box<Error + Sync + Send>> {
|
||||||
raw: &mut R,
|
|
||||||
info: &SessionInfo)
|
|
||||||
-> Result<DateTime<FixedOffset>> {
|
|
||||||
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
|
let utc = try!(DateTime::<UTC>::from_sql(type_, raw, info));
|
||||||
Ok(utc.with_timezone(&FixedOffset::east(0)))
|
Ok(utc.with_timezone(&FixedOffset::east(0)))
|
||||||
}
|
}
|
||||||
@ -97,11 +80,7 @@ impl FromSql for DateTime<FixedOffset> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for DateTime<FixedOffset> {
|
impl ToSql for DateTime<FixedOffset> {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, type_: &Type, w: &mut Vec<u8>, info: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
type_: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
info: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
self.with_timezone(&UTC).to_sql(type_, w, info)
|
self.with_timezone(&UTC).to_sql(type_, w, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,8 +89,8 @@ impl ToSql for DateTime<FixedOffset> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for NaiveDate {
|
impl FromSql for NaiveDate {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<NaiveDate> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<NaiveDate, Box<Error + Sync + Send>> {
|
||||||
let jd = try!(raw.read_i32::<BigEndian>());
|
let jd = try!(types::date_from_sql(raw));
|
||||||
Ok(base().date() + Duration::days(jd as i64))
|
Ok(base().date() + Duration::days(jd as i64))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,17 +98,13 @@ impl FromSql for NaiveDate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for NaiveDate {
|
impl ToSql for NaiveDate {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
_: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
_: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
let jd = (*self - base().date()).num_days();
|
let jd = (*self - base().date()).num_days();
|
||||||
if jd > i32::max_value() as i64 || jd < i32::min_value() as i64 {
|
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)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +113,8 @@ impl ToSql for NaiveDate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for NaiveTime {
|
impl FromSql for NaiveTime {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<NaiveTime> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<NaiveTime, Box<Error + Sync + Send>> {
|
||||||
let usec = try!(raw.read_i64::<BigEndian>());
|
let usec = try!(types::time_from_sql(raw));
|
||||||
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(usec))
|
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(usec))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,17 +122,13 @@ impl FromSql for NaiveTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for NaiveTime {
|
impl ToSql for NaiveTime {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
_: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
_: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
let delta = *self - NaiveTime::from_hms(0, 0, 0);
|
let delta = *self - NaiveTime::from_hms(0, 0, 0);
|
||||||
let time = match delta.num_microseconds() {
|
let time = match delta.num_microseconds() {
|
||||||
Some(time) => time,
|
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)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
extern crate eui48;
|
extern crate eui48;
|
||||||
|
|
||||||
use std::io::prelude::*;
|
|
||||||
|
|
||||||
use self::eui48::MacAddress;
|
use self::eui48::MacAddress;
|
||||||
|
use std::error::Error;
|
||||||
|
use postgres_protocol::types;
|
||||||
|
|
||||||
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
|
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
|
||||||
use Result;
|
|
||||||
|
|
||||||
impl FromSql for MacAddress {
|
impl FromSql for MacAddress {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<MacAddress> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<MacAddress, Box<Error + Sync + Send>> {
|
||||||
let mut bytes = [0; 6];
|
let bytes = try!(types::macaddr_from_sql(raw));
|
||||||
try!(raw.read_exact(&mut bytes));
|
|
||||||
Ok(MacAddress::new(bytes))
|
Ok(MacAddress::new(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,8 +16,10 @@ impl FromSql for MacAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for MacAddress {
|
impl ToSql for MacAddress {
|
||||||
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
try!(w.write_all(self.as_bytes()));
|
let mut bytes = [0; 6];
|
||||||
|
bytes.copy_from_slice(self.as_bytes());
|
||||||
|
types::macaddr_to_sql(bytes, w);
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
351
src/types/mod.rs
351
src/types/mod.rs
@ -1,19 +1,18 @@
|
|||||||
//! Traits dealing with Postgres data types
|
//! Traits dealing with Postgres data types
|
||||||
|
|
||||||
|
use fallible_iterator::FallibleIterator;
|
||||||
|
use postgres_protocol::types::{self, ArrayDimension};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
|
||||||
|
|
||||||
#[doc(inline)]
|
#[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};
|
pub use self::special::{Date, Timestamp};
|
||||||
use {Result, SessionInfoNew, InnerConnection, OtherNew, WrongTypeNew, FieldNew};
|
use {SessionInfoNew, InnerConnection, OtherNew, WrongTypeNew, FieldNew};
|
||||||
use error::Error;
|
|
||||||
|
|
||||||
/// Generates a simple implementation of `ToSql::accepts` which accepts the
|
/// Generates a simple implementation of `ToSql::accepts` which accepts the
|
||||||
/// types passed to it.
|
/// types passed to it.
|
||||||
@ -37,9 +36,9 @@ macro_rules! to_sql_checked {
|
|||||||
() => {
|
() => {
|
||||||
fn to_sql_checked(&self,
|
fn to_sql_checked(&self,
|
||||||
ty: &$crate::types::Type,
|
ty: &$crate::types::Type,
|
||||||
out: &mut ::std::io::Write,
|
out: &mut ::std::vec::Vec<u8>,
|
||||||
ctx: &$crate::types::SessionInfo)
|
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)
|
$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.
|
// WARNING: this function is not considered part of this crate's public API.
|
||||||
// It is subject to change at any time.
|
// It is subject to change at any time.
|
||||||
#[doc(hidden)]
|
#[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
|
where T: ToSql
|
||||||
{
|
{
|
||||||
if !T::accepts(ty) {
|
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)
|
v.to_sql(ty, out, ctx)
|
||||||
}
|
}
|
||||||
@ -73,7 +72,7 @@ mod chrono;
|
|||||||
mod eui48;
|
mod eui48;
|
||||||
|
|
||||||
mod special;
|
mod special;
|
||||||
mod types;
|
mod type_gen;
|
||||||
|
|
||||||
/// A structure providing information for conversion methods.
|
/// A structure providing information for conversion methods.
|
||||||
pub struct SessionInfo<'a> {
|
pub struct SessionInfo<'a> {
|
||||||
@ -214,11 +213,11 @@ pub struct WasNull;
|
|||||||
|
|
||||||
impl fmt::Display for WasNull {
|
impl fmt::Display for WasNull {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
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 {
|
fn description(&self) -> &str {
|
||||||
"a Postgres value was `NULL`"
|
"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 {
|
fn description(&self) -> &str {
|
||||||
"cannot convert to or from a Postgres value"
|
"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
|
/// `FromSql` is implemented for `Vec<T>` where `T` implements `FromSql`, and
|
||||||
/// corresponds to one-dimensional Postgres arrays.
|
/// corresponds to one-dimensional Postgres arrays.
|
||||||
pub trait FromSql: Sized {
|
pub trait FromSql: Sized {
|
||||||
/// Creates a new value of this type from a `Read`er of the binary format
|
/// Creates a new value of this type from a buffer of data of the specified
|
||||||
/// of the specified Postgres `Type`.
|
/// Postgres `Type` in its binary format.
|
||||||
///
|
///
|
||||||
/// The caller of this method is responsible for ensuring that this type
|
/// The caller of this method is responsible for ensuring that this type
|
||||||
/// is compatible with the Postgres `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.
|
/// 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`.
|
/// is compatible with the Postgres `Type`.
|
||||||
///
|
///
|
||||||
/// The default implementation returns
|
/// The default implementation returns
|
||||||
/// `Err(Error::Conversion(Box::new(WasNull))`.
|
/// `Err(Box::new(WasNull))`.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self> {
|
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self, Box<Error + Sync + Send>> {
|
||||||
Err(Error::Conversion(Box::new(WasNull)))
|
Err(Box::new(WasNull))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if a value of this type can be created from the specified
|
/// 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> {
|
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)
|
<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)
|
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> {
|
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() {
|
let member_type = match *ty.kind() {
|
||||||
Kind::Array(ref member) => member,
|
Kind::Array(ref member) => member,
|
||||||
_ => panic!("expected array type"),
|
_ => panic!("expected array type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let dimensions = try!(raw.read_i32::<BigEndian>());
|
let array = try!(types::array_from_sql(raw));
|
||||||
if dimensions > 1 {
|
if try!(array.dimensions().count()) > 1 {
|
||||||
return Err(Error::Conversion("array contains too many dimensions".into()));
|
return Err("array contains too many dimensions".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let _has_nulls = try!(raw.read_i32::<BigEndian>());
|
array.values()
|
||||||
let _member_oid = try!(raw.read_u32::<BigEndian>());
|
.and_then(|v| {
|
||||||
|
match v {
|
||||||
if dimensions == 0 {
|
Some(v) => T::from_sql(&member_type, v, info),
|
||||||
return Ok(vec![]);
|
None => T::from_sql_null(&member_type, info),
|
||||||
}
|
}
|
||||||
|
})
|
||||||
let count = try!(raw.read_i32::<BigEndian>());
|
.collect()
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
@ -395,20 +371,16 @@ impl<T: FromSql> FromSql for Vec<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for Vec<u8> {
|
impl FromSql for Vec<u8> {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Vec<u8>> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<Vec<u8>, Box<Error + Sync + Send>> {
|
||||||
let mut buf = vec![];
|
Ok(types::bytea_from_sql(raw).to_owned())
|
||||||
try!(raw.read_to_end(&mut buf));
|
|
||||||
Ok(buf)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
accepts!(Type::Bytea);
|
accepts!(Type::Bytea);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for String {
|
impl FromSql for String {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<String> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<String, Box<Error + Sync + Send>> {
|
||||||
let mut buf = vec![];
|
types::text_from_sql(raw).map(|b| b.to_owned())
|
||||||
try!(raw.read_to_end(&mut buf));
|
|
||||||
String::from_utf8(buf).map_err(|err| Error::Conversion(Box::new(err)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
@ -420,19 +392,11 @@ impl FromSql for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for i8 {
|
macro_rules! simple_from {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<i8> {
|
|
||||||
Ok(try!(raw.read_i8()))
|
|
||||||
}
|
|
||||||
|
|
||||||
accepts!(Type::Char);
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! primitive_from {
|
|
||||||
($t:ty, $f:ident, $($expected:pat),+) => {
|
($t:ty, $f:ident, $($expected:pat),+) => {
|
||||||
impl FromSql for $t {
|
impl FromSql for $t {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<$t> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<$t, Box<Error + Sync + Send>> {
|
||||||
Ok(try!(raw.$f::<BigEndian>()))
|
types::$f(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
accepts!($($expected),+);
|
accepts!($($expected),+);
|
||||||
@ -440,47 +404,20 @@ macro_rules! primitive_from {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
primitive_from!(i16, read_i16, Type::Int2);
|
simple_from!(bool, bool_from_sql, Type::Bool);
|
||||||
primitive_from!(i32, read_i32, Type::Int4);
|
simple_from!(i8, char_from_sql, Type::Char);
|
||||||
primitive_from!(u32, read_u32, Type::Oid);
|
simple_from!(i16, int2_from_sql, Type::Int2);
|
||||||
primitive_from!(i64, read_i64, Type::Int8);
|
simple_from!(i32, int4_from_sql, Type::Int4);
|
||||||
primitive_from!(f32, read_f32, Type::Float4);
|
simple_from!(u32, oid_from_sql, Type::Oid);
|
||||||
primitive_from!(f64, read_f64, Type::Float8);
|
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>> {
|
impl FromSql for HashMap<String, Option<String>> {
|
||||||
fn from_sql<R: Read>(_: &Type,
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<HashMap<String, Option<String>>, Box<Error + Sync + Send>> {
|
||||||
raw: &mut R,
|
try!(types::hstore_from_sql(raw))
|
||||||
_: &SessionInfo)
|
.map(|(k, v)| (k.to_owned(), v.map(|v| v.to_owned())))
|
||||||
-> Result<HashMap<String, Option<String>>> {
|
.collect()
|
||||||
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 accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
@ -556,7 +493,7 @@ pub enum IsNull {
|
|||||||
/// 1.
|
/// 1.
|
||||||
pub trait ToSql: fmt::Debug {
|
pub trait ToSql: fmt::Debug {
|
||||||
/// Converts the value of `self` into the binary format of the specified
|
/// 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
|
/// The caller of this method is responsible for ensuring that this type
|
||||||
/// is compatible with the Postgres `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
|
/// The return value indicates if this value should be represented as
|
||||||
/// `NULL`. If this is the case, implementations **must not** write
|
/// `NULL`. If this is the case, implementations **must not** write
|
||||||
/// anything to `out`.
|
/// anything to `out`.
|
||||||
fn to_sql<W: ?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>> where Self: Sized;
|
||||||
where Self: Sized,
|
|
||||||
W: Write;
|
|
||||||
|
|
||||||
/// Determines if a value of this type can be converted to the specified
|
/// Determines if a value of this type can be converted to the specified
|
||||||
/// Postgres `Type`.
|
/// Postgres `Type`.
|
||||||
@ -576,35 +511,25 @@ pub trait ToSql: fmt::Debug {
|
|||||||
///
|
///
|
||||||
/// *All* implementations of this method should be generated by the
|
/// *All* implementations of this method should be generated by the
|
||||||
/// `to_sql_checked!()` macro.
|
/// `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
|
impl<'a, T> ToSql for &'a T
|
||||||
where T: ToSql
|
where T: ToSql
|
||||||
{
|
{
|
||||||
to_sql_checked!();
|
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
|
||||||
ty: &Type,
|
|
||||||
out: &mut W,
|
|
||||||
ctx: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
(*self).to_sql(ty, out, ctx)
|
(*self).to_sql(ty, out, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
T::accepts(ty)
|
T::accepts(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to_sql_checked!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ToSql> ToSql for Option<T> {
|
impl<T: ToSql> ToSql for Option<T> {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
|
||||||
ty: &Type,
|
|
||||||
out: &mut W,
|
|
||||||
ctx: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
match *self {
|
match *self {
|
||||||
Some(ref val) => val.to_sql(ty, out, ctx),
|
Some(ref val) => val.to_sql(ty, out, ctx),
|
||||||
None => Ok(IsNull::Yes),
|
None => Ok(IsNull::Yes),
|
||||||
@ -614,55 +539,35 @@ impl<T: ToSql> ToSql for Option<T> {
|
|||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
<T as ToSql>::accepts(ty)
|
<T as ToSql>::accepts(ty)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ToSql for bool {
|
|
||||||
to_sql_checked!();
|
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] {
|
impl<'a, T: ToSql> ToSql for &'a [T] {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
|
||||||
ty: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
ctx: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
let member_type = match *ty.kind() {
|
let member_type = match *ty.kind() {
|
||||||
Kind::Array(ref member) => member,
|
Kind::Array(ref member) => member,
|
||||||
_ => panic!("expected array type"),
|
_ => panic!("expected array type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
try!(w.write_i32::<BigEndian>(1)); // number of dimensions
|
let dimensions = [
|
||||||
try!(w.write_i32::<BigEndian>(1)); // has nulls
|
ArrayDimension {
|
||||||
try!(w.write_u32::<BigEndian>(member_type.oid()));
|
len: try!(downcast(self.len())),
|
||||||
|
lower_bound: 1,
|
||||||
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();
|
];
|
||||||
}
|
|
||||||
|
|
||||||
|
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)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,48 +577,48 @@ impl<'a, T: ToSql> ToSql for &'a [T] {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to_sql_checked!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToSql for &'a [u8] {
|
impl<'a> ToSql for &'a [u8] {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
types::bytea_to_sql(*self, w);
|
||||||
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
|
||||||
try!(w.write_all(*self));
|
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
accepts!(Type::Bytea);
|
accepts!(Type::Bytea);
|
||||||
|
|
||||||
|
to_sql_checked!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ToSql> ToSql for Vec<T> {
|
impl<T: ToSql> ToSql for Vec<T> {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
|
||||||
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
|
||||||
<&[T] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
<&[T] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
<&[T] as ToSql>::accepts(ty)
|
<&[T] as ToSql>::accepts(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to_sql_checked!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Vec<u8> {
|
impl ToSql for Vec<u8> {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
|
||||||
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
|
||||||
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
<&[u8] as ToSql>::accepts(ty)
|
<&[u8] as ToSql>::accepts(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to_sql_checked!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ToSql for &'a str {
|
impl<'a> ToSql for &'a str {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
types::text_to_sql(*self, w);
|
||||||
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
|
||||||
try!(w.write_all(self.as_bytes()));
|
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -724,81 +629,49 @@ impl<'a> ToSql for &'a str {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to_sql_checked!();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for String {
|
impl ToSql for String {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
|
||||||
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
|
||||||
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
|
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(ty: &Type) -> bool {
|
fn accepts(ty: &Type) -> bool {
|
||||||
<&str as ToSql>::accepts(ty)
|
<&str as ToSql>::accepts(ty)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ToSql for i8 {
|
|
||||||
to_sql_checked!();
|
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),+) => {
|
($t:ty, $f:ident, $($expected:pat),+) => {
|
||||||
impl ToSql for $t {
|
impl ToSql for $t {
|
||||||
to_sql_checked!();
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
|
types::$f(*self, w);
|
||||||
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
try!(w.$f::<BigEndian>(*self));
|
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
accepts!($($expected),+);
|
accepts!($($expected),+);
|
||||||
|
|
||||||
|
to_sql_checked!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
to_primitive!(i16, write_i16, Type::Int2);
|
simple_to!(bool, bool_to_sql, Type::Bool);
|
||||||
to_primitive!(i32, write_i32, Type::Int4);
|
simple_to!(i8, char_to_sql, Type::Char);
|
||||||
to_primitive!(u32, write_u32, Type::Oid);
|
simple_to!(i16, int2_to_sql, Type::Int2);
|
||||||
to_primitive!(i64, write_i64, Type::Int8);
|
simple_to!(i32, int4_to_sql, Type::Int4);
|
||||||
to_primitive!(f32, write_f32, Type::Float4);
|
simple_to!(u32, oid_to_sql, Type::Oid);
|
||||||
to_primitive!(f64, write_f64, Type::Float8);
|
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>> {
|
impl ToSql for HashMap<String, Option<String>> {
|
||||||
to_sql_checked!();
|
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));
|
||||||
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)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,11 +681,13 @@ impl ToSql for HashMap<String, Option<String>> {
|
|||||||
_ => false,
|
_ => 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 {
|
if len > i32::max_value() as usize {
|
||||||
Err(Error::Conversion("value too large to transmit".into()))
|
Err("value too large to transmit".into())
|
||||||
} else {
|
} else {
|
||||||
Ok(len as i32)
|
Ok(len as i32)
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,33 @@
|
|||||||
extern crate rustc_serialize;
|
extern crate rustc_serialize;
|
||||||
|
|
||||||
use self::rustc_serialize::json;
|
use self::rustc_serialize::json;
|
||||||
use std::io::prelude::*;
|
use std::io::{Cursor, Write};
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
use byteorder::ReadBytesExt;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
use Result;
|
|
||||||
use error::Error;
|
|
||||||
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
|
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
|
||||||
|
|
||||||
impl FromSql for json::Json {
|
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 {
|
if let Type::Jsonb = *ty {
|
||||||
// We only support version 1 of the jsonb binary format
|
// We only support version 1 of the jsonb binary format
|
||||||
if try!(raw.read_u8()) != 1 {
|
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);
|
accepts!(Type::Json, Type::Jsonb);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for json::Json {
|
impl ToSql for json::Json {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
ty: &Type,
|
|
||||||
mut out: &mut W,
|
|
||||||
_: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
try!(out.write_u8(1));
|
out.push(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(write!(out, "{}", self));
|
try!(write!(out, "{}", self));
|
||||||
|
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,39 +1,32 @@
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::io::prelude::*;
|
use byteorder::ReadBytesExt;
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
|
||||||
use self::serde_json::Value;
|
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};
|
use types::{FromSql, ToSql, IsNull, Type, SessionInfo};
|
||||||
|
|
||||||
impl FromSql for Value {
|
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 {
|
if let Type::Jsonb = *ty {
|
||||||
// We only support version 1 of the jsonb binary format
|
// We only support version 1 of the jsonb binary format
|
||||||
if try!(raw.read_u8()) != 1 {
|
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);
|
accepts!(Type::Json, Type::Jsonb);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Value {
|
impl ToSql for Value {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
ty: &Type,
|
|
||||||
mut out: &mut W,
|
|
||||||
_: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
if let Type::Jsonb = *ty {
|
if let Type::Jsonb = *ty {
|
||||||
try!(out.write_u8(1));
|
out.push(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try!(write!(out, "{:?}", self));
|
try!(write!(out, "{:?}", self));
|
||||||
|
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
use std::io::prelude::*;
|
use postgres_protocol::types;
|
||||||
use std::{i32, i64};
|
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};
|
use types::{Type, FromSql, ToSql, IsNull, SessionInfo};
|
||||||
|
|
||||||
/// A wrapper that can be used to represent infinity with `Type::Date` types.
|
/// 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> {
|
impl<T: FromSql> FromSql for Date<T> {
|
||||||
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>> {
|
||||||
if *ty != Type::Date {
|
match try!(types::date_from_sql(raw)) {
|
||||||
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>()) {
|
|
||||||
i32::MAX => Ok(Date::PosInfinity),
|
i32::MAX => Ok(Date::PosInfinity),
|
||||||
i32::MIN => Ok(Date::NegInfinity),
|
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> {
|
impl<T: ToSql> ToSql for Date<T> {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
ty: &Type,
|
|
||||||
out: &mut W,
|
|
||||||
ctx: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
if *ty != Type::Date {
|
|
||||||
return Err(Error::Conversion("expected date type".into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = match *self {
|
let value = match *self {
|
||||||
Date::PosInfinity => i32::MAX,
|
Date::PosInfinity => i32::MAX,
|
||||||
Date::NegInfinity => i32::MIN,
|
Date::NegInfinity => i32::MIN,
|
||||||
Date::Value(ref v) => return v.to_sql(ty, out, ctx),
|
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)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,18 +60,11 @@ pub enum Timestamp<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FromSql> FromSql for Timestamp<T> {
|
impl<T: FromSql> FromSql for Timestamp<T> {
|
||||||
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>> {
|
||||||
if *ty != Type::Timestamp && *ty != Type::Timestamptz {
|
match try!(types::timestamp_from_sql(raw)) {
|
||||||
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>()) {
|
|
||||||
i64::MAX => Ok(Timestamp::PosInfinity),
|
i64::MAX => Ok(Timestamp::PosInfinity),
|
||||||
i64::MIN => Ok(Timestamp::NegInfinity),
|
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> {
|
impl<T: ToSql> ToSql for Timestamp<T> {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = match *self {
|
let value = match *self {
|
||||||
Timestamp::PosInfinity => i64::MAX,
|
Timestamp::PosInfinity => i64::MAX,
|
||||||
Timestamp::NegInfinity => i64::MIN,
|
Timestamp::NegInfinity => i64::MIN,
|
||||||
Timestamp::Value(ref v) => return v.to_sql(ty, out, ctx),
|
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)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
|
||||||
use self::time::Timespec;
|
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};
|
use types::{Type, FromSql, ToSql, IsNull, SessionInfo};
|
||||||
|
|
||||||
const USEC_PER_SEC: i64 = 1_000_000;
|
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;
|
const TIME_SEC_CONVERSION: i64 = 946684800;
|
||||||
|
|
||||||
impl FromSql for Timespec {
|
impl FromSql for Timespec {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Timespec> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<Timespec, Box<Error + Sync + Send>> {
|
||||||
let t = try!(raw.read_i64::<BigEndian>());
|
let t = try!(types::timestamp_from_sql(raw));
|
||||||
let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION;
|
let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION;
|
||||||
let mut usec = t % USEC_PER_SEC;
|
let mut usec = t % USEC_PER_SEC;
|
||||||
|
|
||||||
@ -31,13 +30,9 @@ impl FromSql for Timespec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Timespec {
|
impl ToSql for Timespec {
|
||||||
fn to_sql<W: Write + ?Sized>(&self,
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
_: &Type,
|
|
||||||
mut w: &mut W,
|
|
||||||
_: &SessionInfo)
|
|
||||||
-> Result<IsNull> {
|
|
||||||
let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC;
|
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)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
|
|
||||||
use std::io::prelude::*;
|
use postgres_protocol::types;
|
||||||
|
|
||||||
use self::uuid::Uuid;
|
use self::uuid::Uuid;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
|
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
|
||||||
use Result;
|
|
||||||
|
|
||||||
impl FromSql for Uuid {
|
impl FromSql for Uuid {
|
||||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Uuid> {
|
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<Uuid, Box<Error + Sync + Send>> {
|
||||||
let mut bytes = [0; 16];
|
let bytes = try!(types::uuid_from_sql(raw));
|
||||||
try!(raw.read_exact(&mut bytes));
|
|
||||||
Ok(Uuid::from_bytes(&bytes).unwrap())
|
Ok(Uuid::from_bytes(&bytes).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,8 +16,8 @@ impl FromSql for Uuid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql for Uuid {
|
impl ToSql for Uuid {
|
||||||
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
fn to_sql(&self, _: &Type, w: &mut Vec<u8>, _: &SessionInfo) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||||
try!(w.write_all(self.as_bytes()));
|
types::uuid_to_sql(*self.as_bytes(), w);
|
||||||
Ok(IsNull::No)
|
Ok(IsNull::No)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::error;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
use std::result;
|
||||||
|
|
||||||
use postgres::{Connection, TlsMode, Result};
|
use postgres::{Connection, TlsMode, Result};
|
||||||
use postgres::error::Error;
|
use postgres::error::Error;
|
||||||
@ -251,9 +253,7 @@ fn domain() {
|
|||||||
struct SessionId(Vec<u8>);
|
struct SessionId(Vec<u8>);
|
||||||
|
|
||||||
impl ToSql for SessionId {
|
impl ToSql for SessionId {
|
||||||
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
|
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>, ctx: &SessionInfo) -> result::Result<IsNull, Box<error::Error + Sync + Send>> {
|
||||||
where W: Write
|
|
||||||
{
|
|
||||||
let inner = match *ty.kind() {
|
let inner = match *ty.kind() {
|
||||||
Kind::Domain(ref inner) => inner,
|
Kind::Domain(ref inner) => inner,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -269,7 +269,7 @@ fn domain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FromSql for SessionId {
|
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)
|
Vec::<u8>::from_sql(ty, raw, ctx).map(SessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user