diff --git a/src/error.rs b/src/error.rs index 13b1092d..a3a1286f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,6 +7,8 @@ use std::io::IoError; use openssl::ssl::error::SslError; use phf::PhfMap; +use types::PostgresType; + macro_rules! make_errors( ($($code:expr => $error:ident),+) => ( /// SQLSTATE error codes @@ -514,7 +516,10 @@ pub enum PostgresError { expected: uint, /// The actual number of parameters actual: uint, - } + }, + /// An attempt was made to convert between incompatible Rust and Postgres + /// types + PgWrongType(PostgresType) } impl PostgresError { @@ -532,6 +537,7 @@ impl PostgresError { prepared on ", PgWrongParamCount { expected, actual } => format!("Expected {} parameters but got {}", expected, actual), + PgWrongType(ref ty) => format!("Unexpected type {}", *ty), } } } diff --git a/src/lib.rs b/src/lib.rs index d91f0526..4de99e5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -977,11 +977,6 @@ impl<'conn> PostgresTransaction<'conn> { /// No more than `row_limit` rows will be stored in memory at a time. Rows /// will be pulled from the database in batches of `row_limit` as needed. /// If `row_limit` is 0, `lazy_query` is equivalent to `query`. - /// - /// # Failure - /// - /// Fails if the types of the provided parameters do not match the - /// parameters of the statement. pub fn lazy_query<'trans, 'stmt>(&'trans self, stmt: &'stmt PostgresStatement, params: &[&ToSql], @@ -1058,7 +1053,7 @@ impl<'conn> PostgresStatement<'conn> { }); } for (¶m, ty) in params.iter().zip(self.param_types.iter()) { - let (format, value) = param.to_sql(ty); + let (format, value) = try!(param.to_sql(ty)); formats.push(format as i16); values.push(value); }; @@ -1126,11 +1121,6 @@ impl<'conn> PostgresStatement<'conn> { /// /// If the statement does not modify any rows (e.g. SELECT), 0 is returned. /// - /// # Failure - /// - /// Fails if the types of the provided parameters do not match the - /// parameters of the statement. - /// /// # Example /// /// ```rust,no_run @@ -1179,11 +1169,6 @@ impl<'conn> PostgresStatement<'conn> { /// Executes the prepared statement, returning an iterator over the /// resulting rows. /// - /// # Failure - /// - /// Fails if the types of the provided parameters do not match the - /// parameters of the statement. - /// /// # Example /// /// ```rust,no_run @@ -1375,7 +1360,7 @@ impl<'stmt> Container for PostgresRow<'stmt> { impl<'stmt, I: RowIndex, T: FromSql> Index for PostgresRow<'stmt> { fn index(&self, idx: &I) -> T { let idx = idx.idx(self.stmt); - FromSql::from_sql(&self.stmt.result_desc.get(idx).ty, self.data.get(idx)) + FromSql::from_sql(&self.stmt.result_desc.get(idx).ty, self.data.get(idx)).unwrap() } } diff --git a/src/test.rs b/src/test.rs index 1d36344f..5926c3ef 100644 --- a/src/test.rs +++ b/src/test.rs @@ -21,6 +21,7 @@ use error::{PgConnectDbError, PgDbError, PgWrongConnection, PgWrongParamCount, + PgWrongType, DnsError, MissingPassword, Position, @@ -34,6 +35,15 @@ use types::array::{ArrayBase}; use types::range::{Range, Inclusive, Exclusive, RangeBound}; use pool::PostgresConnectionPool; +macro_rules! or_fail( + ($e:expr) => ( + match $e { + Ok(ok) => ok, + Err(err) => fail!("{}", err) + } + ) +) + #[test] // Make sure we can take both connections at once and can still get one after fn test_pool() { @@ -700,10 +710,12 @@ fn test_f64_nan_param() { } #[test] -#[should_fail] fn test_wrong_param_type() { let conn = or_fail!(PostgresConnection::connect("postgres://postgres@localhost", &NoSsl)); - let _ = conn.execute("SELECT $1::VARCHAR", [&1i32 as &ToSql]); + match conn.execute("SELECT $1::VARCHAR", [&1i32 as &ToSql]) { + Err(PgWrongType(_)) => {} + res => fail!("unexpected result {}", res) + } } #[test] diff --git a/src/types/mod.rs b/src/types/mod.rs index 8f4ee83f..2fe639ba 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -10,8 +10,9 @@ use std::io::util::LimitReader; use std::str; use time::Timespec; -use self::array::{Array, ArrayBase, DimensionInfo}; -use self::range::{RangeBound, Inclusive, Exclusive, Range}; +use error::{PostgresError, PgWrongType, PgStreamError}; +use types::array::{Array, ArrayBase, DimensionInfo}; +use types::range::{RangeBound, Inclusive, Exclusive, Range}; pub mod array; pub mod range; @@ -74,7 +75,7 @@ static RANGE_EMPTY: i8 = 0b0000_0001; macro_rules! make_postgres_type( ($($doc:attr $oid:ident => $variant:ident $(member $member:ident)*),+) => ( /// A Postgres type - #[deriving(Eq, Show)] + #[deriving(Eq, Clone, Show)] pub enum PostgresType { $( $doc @@ -218,17 +219,8 @@ pub enum Format { macro_rules! check_types( ($($expected:pat)|+, $actual:ident) => ( match $actual { - $(&$expected)|+ => (), - actual => fail!("Invalid Postgres type {}", *actual) - } - ) -) - -macro_rules! or_fail( - ($e:expr) => ( - match $e { - Ok(ok) => ok, - Err(err) => fail!("{}", err) + $(&$expected)|+ => {} + actual => return Err(PgWrongType(actual.clone())) } ) ) @@ -238,43 +230,44 @@ pub trait FromSql { /// Creates a new value of this type from a buffer of Postgres data. /// /// If the value was `NULL`, the buffer will be `None`. - /// - /// # Failure - /// - /// Fails if this type can not be created from the provided Postgres type. - fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) -> Self; + fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) + -> Result; } #[doc(hidden)] trait RawFromSql { - fn raw_from_sql(raw: &mut R) -> Self; + fn raw_from_sql(raw: &mut R) -> Result; } macro_rules! raw_from_impl( ($t:ty, $f:ident) => ( impl RawFromSql for $t { - fn raw_from_sql(raw: &mut R) -> $t { - or_fail!(raw.$f()) + fn raw_from_sql(raw: &mut R) + -> Result<$t, PostgresError> { + Ok(try_pg!(raw.$f())) } } ) ) impl RawFromSql for bool { - fn raw_from_sql(raw: &mut R) -> bool { - (or_fail!(raw.read_u8())) != 0 + fn raw_from_sql(raw: &mut R) + -> Result { + Ok((try_pg!(raw.read_u8())) != 0) } } impl RawFromSql for ~[u8] { - fn raw_from_sql(raw: &mut R) -> ~[u8] { - or_fail!(raw.read_to_end()) + fn raw_from_sql(raw: &mut R) + -> Result<~[u8], PostgresError> { + Ok(try_pg!(raw.read_to_end())) } } impl RawFromSql for ~str { - fn raw_from_sql(raw: &mut R) -> ~str { - str::from_utf8_owned(or_fail!(raw.read_to_end())).unwrap() + fn raw_from_sql(raw: &mut R) + -> Result<~str, PostgresError> { + Ok(str::from_utf8_owned(try_pg!(raw.read_to_end())).unwrap()) } } @@ -286,8 +279,9 @@ raw_from_impl!(f32, read_be_f32) raw_from_impl!(f64, read_be_f64) impl RawFromSql for Timespec { - fn raw_from_sql(raw: &mut R) -> Timespec { - let t = or_fail!(raw.read_be_i64()); + fn raw_from_sql(raw: &mut R) + -> Result { + let t = try_pg!(raw.read_be_i64()); let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION; let mut usec = t % USEC_PER_SEC; @@ -296,24 +290,26 @@ impl RawFromSql for Timespec { usec = USEC_PER_SEC + usec; } - Timespec::new(sec, (usec * NSEC_PER_USEC) as i32) + Ok(Timespec::new(sec, (usec * NSEC_PER_USEC) as i32)) } } impl RawFromSql for Uuid { - fn raw_from_sql(raw: &mut R) -> Uuid { - Uuid::from_bytes(or_fail!(raw.read_to_end())).unwrap() + fn raw_from_sql(raw: &mut R) + -> Result { + Ok(Uuid::from_bytes(try_pg!(raw.read_to_end())).unwrap()) } } macro_rules! from_range_impl( ($($oid:ident)|+, $t:ty) => ( impl RawFromSql for Range<$t> { - fn raw_from_sql(rdr: &mut R) -> Range<$t> { - let t = or_fail!(rdr.read_i8()); + fn raw_from_sql(rdr: &mut R) + -> Result, PostgresError> { + let t = try_pg!(rdr.read_i8()); if t & RANGE_EMPTY != 0 { - Range::empty() + Ok(Range::empty()) } else { let lower = match t & RANGE_LOWER_UNBOUNDED { 0 => { @@ -321,10 +317,10 @@ macro_rules! from_range_impl( 0 => Exclusive, _ => Inclusive }; - let len = or_fail!(rdr.read_be_i32()) as uint; + let len = try_pg!(rdr.read_be_i32()) as uint; let mut limit = LimitReader::new(rdr.by_ref(), len); let lower = Some(RangeBound::new( - RawFromSql::raw_from_sql(&mut limit), type_)); + try!(RawFromSql::raw_from_sql(&mut limit)), type_)); assert!(limit.limit() == 0); lower } @@ -336,17 +332,17 @@ macro_rules! from_range_impl( 0 => Exclusive, _ => Inclusive }; - let len = or_fail!(rdr.read_be_i32()) as uint; + let len = try_pg!(rdr.read_be_i32()) as uint; let mut limit = LimitReader::new(rdr.by_ref(), len); let upper = Some(RangeBound::new( - RawFromSql::raw_from_sql(&mut limit), type_)); + try!(RawFromSql::raw_from_sql(&mut limit)), type_)); assert!(limit.limit() == 0); upper } _ => None }; - Range::new(lower, upper) + Ok(Range::new(lower, upper)) } } } @@ -358,25 +354,31 @@ from_range_impl!(PgInt8Range, i64) from_range_impl!(PgTsRange | PgTstzRange, Timespec) impl RawFromSql for Json { - fn raw_from_sql(raw: &mut R) -> Json { - json::from_reader(raw as &mut Reader).unwrap() + fn raw_from_sql(raw: &mut R) + -> Result { + Ok(json::from_reader(raw as &mut Reader).unwrap()) } } macro_rules! from_map_impl( ($($expected:pat)|+, $t:ty, $blk:expr) => ( impl FromSql for Option<$t> { - fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) -> Option<$t> { + fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) + -> Result, PostgresError> { check_types!($($expected)|+, ty) - raw.as_ref().map($blk) + match *raw { + Some(ref buf) => ($blk)(buf).map(|ok| Some(ok)), + None => Ok(None) + } } } impl FromSql for $t { - fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) -> $t { + fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) + -> Result<$t, PostgresError> { // FIXME when you can specify Self types properly - let ret: Option<$t> = FromSql::from_sql(ty, raw); - ret.unwrap() + let ret: Result, PostgresError> = FromSql::from_sql(ty, raw); + ret.map(|ok| ok.unwrap()) } } ) @@ -384,7 +386,7 @@ macro_rules! from_map_impl( macro_rules! from_raw_from_impl( ($($expected:pat)|+, $t:ty) => ( - from_map_impl!($($expected)|+, $t, |buf| { + from_map_impl!($($expected)|+, $t, |buf: &~[u8]| { let mut reader = BufReader::new(buf.as_slice()); RawFromSql::raw_from_sql(&mut reader) }) @@ -410,35 +412,35 @@ from_raw_from_impl!(PgTsRange | PgTstzRange, Range) macro_rules! from_array_impl( ($($oid:ident)|+, $t:ty) => ( - from_map_impl!($($oid)|+, ArrayBase>, |buf| { + from_map_impl!($($oid)|+, ArrayBase>, |buf: &~[u8]| { let mut rdr = BufReader::new(buf.as_slice()); - let ndim = or_fail!(rdr.read_be_i32()) as uint; - let _has_null = or_fail!(rdr.read_be_i32()) == 1; - let _element_type: Oid = or_fail!(rdr.read_be_u32()); + let ndim = try_pg!(rdr.read_be_i32()) as uint; + let _has_null = try_pg!(rdr.read_be_i32()) == 1; + let _element_type: Oid = try_pg!(rdr.read_be_u32()); let mut dim_info = Vec::with_capacity(ndim); for _ in range(0, ndim) { dim_info.push(DimensionInfo { - len: or_fail!(rdr.read_be_i32()) as uint, - lower_bound: or_fail!(rdr.read_be_i32()) as int + len: try_pg!(rdr.read_be_i32()) as uint, + lower_bound: try_pg!(rdr.read_be_i32()) as int }); } let nele = dim_info.iter().fold(1, |acc, info| acc * info.len); let mut elements = Vec::with_capacity(nele); for _ in range(0, nele) { - let len = or_fail!(rdr.read_be_i32()); + let len = try_pg!(rdr.read_be_i32()); if len < 0 { elements.push(None); } else { let mut limit = LimitReader::new(rdr.by_ref(), len as uint); - elements.push(Some(RawFromSql::raw_from_sql(&mut limit))); + elements.push(Some(try!(RawFromSql::raw_from_sql(&mut limit)))); assert!(limit.limit() == 0); } } - ArrayBase::from_raw(elements, dim_info) + Ok(ArrayBase::from_raw(elements, dim_info)) }) ) ) @@ -461,94 +463,105 @@ from_array_impl!(PgInt8RangeArray, Range) impl FromSql for Option>> { fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) - -> Option>> { + -> Result>>, PostgresError> { match *ty { PgUnknownType { name: ref name, .. } if "hstore" == *name => {} - _ => fail!("Invalid Postgres type {}", *ty) + _ => return Err(PgWrongType(ty.clone())) } - raw.as_ref().map(|buf| { - let mut rdr = BufReader::new(buf.as_slice()); - let mut map = HashMap::new(); + match *raw { + Some(ref buf) => { + let mut rdr = BufReader::new(buf.as_slice()); + let mut map = HashMap::new(); - let count = or_fail!(rdr.read_be_i32()); + let count = try_pg!(rdr.read_be_i32()); - for _ in range(0, count) { - let key_len = or_fail!(rdr.read_be_i32()); - let key = str::from_utf8_owned(or_fail!(rdr.read_exact(key_len as uint))).unwrap(); + for _ in range(0, count) { + let key_len = try_pg!(rdr.read_be_i32()); + let key = str::from_utf8_owned(try_pg!(rdr.read_exact(key_len as uint))).unwrap(); - let val_len = or_fail!(rdr.read_be_i32()); - let val = if val_len < 0 { - None - } else { - Some(str::from_utf8_owned(or_fail!(rdr.read_exact(val_len as uint))).unwrap()) - }; + let val_len = try_pg!(rdr.read_be_i32()); + let val = if val_len < 0 { + None + } else { + Some(str::from_utf8_owned(try_pg!(rdr.read_exact(val_len as uint))).unwrap()) + }; - map.insert(key, val); + map.insert(key, val); + } + Ok(Some(map)) } - - map - }) + None => Ok(None) + } } } impl FromSql for HashMap<~str, Option<~str>> { fn from_sql(ty: &PostgresType, raw: &Option<~[u8]>) - -> HashMap<~str, Option<~str>> { + -> Result>, PostgresError> { // FIXME when you can specify Self types properly - let ret: Option>> = FromSql::from_sql(ty, raw); - ret.unwrap() + let ret: Result>>, PostgresError> = FromSql::from_sql(ty, raw); + ret.map(|ok| ok.unwrap()) } } +macro_rules! or_fail( + ($e:expr) => ( + match $e { + Ok(ok) => ok, + Err(err) => fail!("{}", err) + } + ) +) /// A trait for types that can be converted into Postgres values pub trait ToSql { /// Converts the value of `self` into a format appropriate for the Postgres /// backend. - /// - /// # Failure - /// - /// Fails if this type cannot be converted into the specified Postgres - /// type. - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>); + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError>; } #[doc(hidden)] trait RawToSql { - fn raw_to_sql(&self, w: &mut W); + fn raw_to_sql(&self, w: &mut W) -> Result<(), PostgresError>; } macro_rules! raw_to_impl( ($t:ty, $f:ident) => ( impl RawToSql for $t { - fn raw_to_sql(&self, w: &mut W) { - or_fail!(w.$f(*self)) + fn raw_to_sql(&self, w: &mut W) + -> Result<(), PostgresError> { + Ok(try_pg!(w.$f(*self))) } } ) ) impl RawToSql for bool { - fn raw_to_sql(&self, w: &mut W) { - or_fail!(w.write_u8(*self as u8)) + fn raw_to_sql(&self, w: &mut W) + -> Result<(), PostgresError> { + Ok(try_pg!(w.write_u8(*self as u8))) } } impl RawToSql for ~[u8] { - fn raw_to_sql(&self, w: &mut W) { - or_fail!(w.write(self.as_slice())) + fn raw_to_sql(&self, w: &mut W) + -> Result<(), PostgresError> { + Ok(try_pg!(w.write(self.as_slice()))) } } impl RawToSql for Vec { - fn raw_to_sql(&self, w: &mut W) { - or_fail!(w.write(self.as_slice())) + fn raw_to_sql(&self, w: &mut W) + -> Result<(), PostgresError> { + Ok(try_pg!(w.write(self.as_slice()))) } } impl RawToSql for ~str { - fn raw_to_sql(&self, w: &mut W) { - or_fail!(w.write(self.as_bytes())) + fn raw_to_sql(&self, w: &mut W) + -> Result<(), PostgresError> { + Ok(try_pg!(w.write(self.as_bytes()))) } } @@ -560,23 +573,26 @@ raw_to_impl!(f32, write_be_f32) raw_to_impl!(f64, write_be_f64) impl RawToSql for Timespec { - fn raw_to_sql(&self, w: &mut W) { + fn raw_to_sql(&self, w: &mut W) + -> Result<(), PostgresError> { let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC; - or_fail!(w.write_be_i64(t)) + Ok(try_pg!(w.write_be_i64(t))) } } impl RawToSql for Uuid { - fn raw_to_sql(&self, w: &mut W) { - or_fail!(w.write(self.as_bytes())) + fn raw_to_sql(&self, w: &mut W) + -> Result<(), PostgresError> { + Ok(try_pg!(w.write(self.as_bytes()))) } } macro_rules! to_range_impl( ($($oid:ident)|+, $t:ty) => ( impl RawToSql for Range<$t> { - fn raw_to_sql(&self, buf: &mut W) { + fn raw_to_sql(&self, buf: &mut W) + -> Result<(), PostgresError> { let mut tag = 0; if self.is_empty() { tag |= RANGE_EMPTY; @@ -595,28 +611,30 @@ macro_rules! to_range_impl( } } - or_fail!(buf.write_i8(tag)); + try_pg!(buf.write_i8(tag)); match self.lower() { Some(bound) => { let mut inner_buf = MemWriter::new(); - bound.value.raw_to_sql(&mut inner_buf); + try!(bound.value.raw_to_sql(&mut inner_buf)); let inner_buf = inner_buf.unwrap(); - or_fail!(buf.write_be_i32(inner_buf.len() as i32)); - or_fail!(buf.write(inner_buf)); + try_pg!(buf.write_be_i32(inner_buf.len() as i32)); + try_pg!(buf.write(inner_buf)); } None => {} } match self.upper() { Some(bound) => { let mut inner_buf = MemWriter::new(); - bound.value.raw_to_sql(&mut inner_buf); + try!(bound.value.raw_to_sql(&mut inner_buf)); let inner_buf = inner_buf.unwrap(); - or_fail!(buf.write_be_i32(inner_buf.len() as i32)); - or_fail!(buf.write(inner_buf)); + try_pg!(buf.write_be_i32(inner_buf.len() as i32)); + try_pg!(buf.write(inner_buf)); } None => {} } + + Ok(()) } } ) @@ -627,19 +645,21 @@ to_range_impl!(PgInt8Range, i64) to_range_impl!(PgTsRange | PgTstzRange, Timespec) impl RawToSql for Json { - fn raw_to_sql(&self, raw: &mut W) { - or_fail!(self.to_writer(raw as &mut Writer)) + fn raw_to_sql(&self, raw: &mut W) + -> Result<(), PostgresError> { + Ok(try_pg!(self.to_writer(raw as &mut Writer))) } } macro_rules! to_option_impl( ($($oid:pat)|+, $t:ty) => ( impl ToSql for Option<$t> { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { check_types!($($oid)|+, ty) match *self { - None => (Text, None), + None => Ok((Text, None)), Some(ref val) => val.to_sql(ty) } } @@ -650,11 +670,12 @@ macro_rules! to_option_impl( macro_rules! to_option_impl_lifetime( ($($oid:pat)|+, $t:ty) => ( impl<'a> ToSql for Option<$t> { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { check_types!($($oid)|+, ty) match *self { - None => (Text, None), + None => Ok((Text, None)), Some(ref val) => val.to_sql(ty) } } @@ -665,12 +686,13 @@ macro_rules! to_option_impl_lifetime( macro_rules! to_raw_to_impl( ($($oid:ident)|+, $t:ty) => ( impl ToSql for $t { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { check_types!($($oid)|+, ty) let mut writer = MemWriter::new(); - self.raw_to_sql(&mut writer); - (Binary, Some(writer.unwrap())) + try!(self.raw_to_sql(&mut writer)); + Ok((Binary, Some(writer.unwrap()))) } } @@ -694,18 +716,20 @@ to_raw_to_impl!(PgInt8Range, Range) to_raw_to_impl!(PgTsRange | PgTstzRange, Range) impl<'a> ToSql for &'a str { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { check_types!(PgVarchar | PgText | PgCharN, ty) - (Text, Some(self.as_bytes().to_owned())) + Ok((Text, Some(self.as_bytes().to_owned()))) } } to_option_impl_lifetime!(PgVarchar | PgText | PgCharN, &'a str) impl<'a> ToSql for &'a [u8] { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { check_types!(PgByteA, ty) - (Binary, Some(self.to_owned())) + Ok((Binary, Some(self.to_owned()))) } } @@ -717,33 +741,34 @@ to_raw_to_impl!(PgUuid, Uuid) macro_rules! to_array_impl( ($($oid:ident)|+, $t:ty) => ( impl ToSql for ArrayBase> { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { check_types!($($oid)|+, ty) let mut buf = MemWriter::new(); - or_fail!(buf.write_be_i32(self.dimension_info().len() as i32)); - or_fail!(buf.write_be_i32(1)); - or_fail!(buf.write_be_u32(ty.member_type().to_oid())); + try_pg!(buf.write_be_i32(self.dimension_info().len() as i32)); + try_pg!(buf.write_be_i32(1)); + try_pg!(buf.write_be_u32(ty.member_type().to_oid())); for info in self.dimension_info().iter() { - or_fail!(buf.write_be_i32(info.len as i32)); - or_fail!(buf.write_be_i32(info.lower_bound as i32)); + try_pg!(buf.write_be_i32(info.len as i32)); + try_pg!(buf.write_be_i32(info.lower_bound as i32)); } for v in self.values() { match *v { Some(ref val) => { let mut inner_buf = MemWriter::new(); - val.raw_to_sql(&mut inner_buf); + try!(val.raw_to_sql(&mut inner_buf)); let inner_buf = inner_buf.unwrap(); - or_fail!(buf.write_be_i32(inner_buf.len() as i32)); - or_fail!(buf.write(inner_buf)); + try_pg!(buf.write_be_i32(inner_buf.len() as i32)); + try_pg!(buf.write(inner_buf)); } - None => or_fail!(buf.write_be_i32(-1)) + None => try_pg!(buf.write_be_i32(-1)) } } - (Binary, Some(buf.unwrap())) + Ok((Binary, Some(buf.unwrap()))) } } @@ -769,43 +794,45 @@ to_array_impl!(PgInt8RangeArray, Range) to_array_impl!(PgJsonArray, Json) impl ToSql for HashMap<~str, Option<~str>> { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { match *ty { PgUnknownType { name: ref name, .. } if "hstore" == *name => {} - _ => fail!("Invalid Postgres type {}", *ty) + _ => return Err(PgWrongType(ty.clone())) } let mut buf = MemWriter::new(); - or_fail!(buf.write_be_i32(self.len() as i32)); + try_pg!(buf.write_be_i32(self.len() as i32)); for (key, val) in self.iter() { - or_fail!(buf.write_be_i32(key.len() as i32)); - or_fail!(buf.write(key.as_bytes())); + try_pg!(buf.write_be_i32(key.len() as i32)); + try_pg!(buf.write(key.as_bytes())); match *val { Some(ref val) => { - or_fail!(buf.write_be_i32(val.len() as i32)); - or_fail!(buf.write(val.as_bytes())); + try_pg!(buf.write_be_i32(val.len() as i32)); + try_pg!(buf.write(val.as_bytes())); } - None => or_fail!(buf.write_be_i32(-1)) + None => try_pg!(buf.write_be_i32(-1)) } } - (Binary, Some(buf.unwrap())) + Ok((Binary, Some(buf.unwrap()))) } } impl ToSql for Option>> { - fn to_sql(&self, ty: &PostgresType) -> (Format, Option<~[u8]>) { + fn to_sql(&self, ty: &PostgresType) + -> Result<(Format, Option<~[u8]>), PostgresError> { match *ty { PgUnknownType { name: ref name, .. } if "hstore" == *name => {} - _ => fail!("Invalid Postgres type {}", *ty) + _ => return Err(PgWrongType(ty.clone())) } match *self { Some(ref inner) => inner.to_sql(ty), - None => (Binary, None) + None => Ok((Binary, None)) } } }