diff --git a/src/error.rs b/src/error.rs index 602139db..1d1740f8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,13 +1,13 @@ //! Postgres errors use std::collections::HashMap; -use std::from_str::FromStr; use std::io; use std::fmt; use openssl::ssl::error; use phf::PhfMap; +use PostgresResult; use types::PostgresType; macro_rules! make_errors( @@ -480,33 +480,49 @@ pub struct PostgresDbError { impl PostgresDbError { #[doc(hidden)] - pub fn new(fields: Vec<(u8, String)>) -> PostgresDbError { + pub fn new_raw(fields: Vec<(u8, String)>) -> Result { let mut map: HashMap<_, _> = fields.into_iter().collect(); - PostgresDbError { - severity: map.pop(&('S' as u8)).unwrap(), - code: PostgresSqlState::from_code(map.pop(&('C' as u8)).unwrap().as_slice()), - message: map.pop(&('M' as u8)).unwrap(), - detail: map.pop(&('D' as u8)), - hint: map.pop(&('H' as u8)), - position: match map.pop(&('P' as u8)) { - Some(pos) => Some(Position(FromStr::from_str(pos.as_slice()).unwrap())), - None => match map.pop(&('p' as u8)) { + Ok(PostgresDbError { + severity: try!(map.pop(&b'S').ok_or(())), + code: PostgresSqlState::from_code(try!(map.pop(&b'C').ok_or(())).as_slice()), + message: try!(map.pop(&b'M').ok_or(())), + detail: map.pop(&b'D'), + hint: map.pop(&b'H'), + position: match map.pop(&b'P') { + Some(pos) => Some(Position(try!(from_str(pos.as_slice()).ok_or(())))), + None => match map.pop(&b'p') { Some(pos) => Some(InternalPosition { - position: FromStr::from_str(pos.as_slice()).unwrap(), - query: map.pop(&('q' as u8)).unwrap() + position: try!(from_str(pos.as_slice()).ok_or(())), + query: try!(map.pop(&b'q').ok_or(())) }), None => None } }, - where_: map.pop(&('W' as u8)), - schema: map.pop(&('s' as u8)), - table: map.pop(&('t' as u8)), - column: map.pop(&('c' as u8)), - datatype: map.pop(&('d' as u8)), - constraint: map.pop(&('n' as u8)), - file: map.pop(&('F' as u8)).unwrap(), - line: FromStr::from_str(map.pop(&('L' as u8)).unwrap().as_slice()).unwrap(), - routine: map.pop(&('R' as u8)).unwrap() + where_: map.pop(&b'W'), + schema: map.pop(&b's'), + table: map.pop(&b't'), + column: map.pop(&b'c'), + datatype: map.pop(&b'd'), + constraint: map.pop(&b'n'), + file: try!(map.pop(&b'F').ok_or(())), + line: try!(map.pop(&b'L').and_then(|l| from_str(l.as_slice())).ok_or(())), + routine: map.pop(&b'R').unwrap() + }) + } + + #[doc(hidden)] + pub fn new_connect(fields: Vec<(u8, String)>) -> Result { + match PostgresDbError::new_raw(fields) { + Ok(err) => Err(PgConnectDbError(err)), + Err(()) => Err(PgConnectBadResponse), + } + } + + #[doc(hidden)] + pub fn new(fields: Vec<(u8, String)>) -> PostgresResult { + match PostgresDbError::new_raw(fields) { + Ok(err) => Err(PgDbError(err)), + Err(()) => Err(PgBadData), } } } diff --git a/src/lib.rs b/src/lib.rs index 5a271185..0596122b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,10 +80,8 @@ use std::fmt; use error::{InvalidUrl, MissingPassword, MissingUser, - PgConnectDbError, PgConnectStreamError, PgConnectBadResponse, - PgDbError, PgInvalidColumn, PgStreamDesynchronized, PgStreamError, @@ -428,7 +426,7 @@ impl InnerPostgresConnection { } ReadyForQuery { .. } => break, ErrorResponse { fields } => - return Err(PgConnectDbError(PostgresDbError::new(fields))), + return PostgresDbError::new_connect(fields), _ => return Err(PgConnectBadResponse), } } @@ -449,7 +447,10 @@ impl InnerPostgresConnection { loop { match try_desync!(self, self.stream.read_message()) { NoticeResponse { fields } => { - self.notice_handler.handle(PostgresDbError::new(fields)) + match PostgresDbError::new_raw(fields) { + Ok(err) => self.notice_handler.handle(err), + Err(()) => {} + } } NotificationResponse { pid, channel, payload } => { self.notifications.push(PostgresNotification { @@ -500,7 +501,7 @@ impl InnerPostgresConnection { | AuthenticationSCMCredential | AuthenticationGSS | AuthenticationSSPI => return Err(UnsupportedAuthentication), - ErrorResponse { fields } => return Err(PgConnectDbError(PostgresDbError::new(fields))), + ErrorResponse { fields } => return PostgresDbError::new_connect(fields), _ => { self.desynchronized = true; return Err(PgConnectBadResponse); @@ -509,7 +510,7 @@ impl InnerPostgresConnection { match try_pg_conn!(self.read_message_()) { AuthenticationOk => Ok(()), - ErrorResponse { fields } => Err(PgConnectDbError(PostgresDbError::new(fields))), + ErrorResponse { fields } => return PostgresDbError::new_connect(fields), _ => { self.desynchronized = true; return Err(PgConnectBadResponse); @@ -543,7 +544,7 @@ impl InnerPostgresConnection { ParseComplete => {} ErrorResponse { fields } => { try!(self.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } _ => bad_response!(self), } @@ -629,7 +630,7 @@ impl InnerPostgresConnection { ReadyForQuery { .. } => break, ErrorResponse { fields } => { try!(self.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } _ => {} } @@ -691,7 +692,7 @@ impl InnerPostgresConnection { } ErrorResponse { fields } => { try!(self.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } _ => {} } @@ -1184,7 +1185,7 @@ impl<'conn> PostgresStatement<'conn> { BindComplete => Ok(()), ErrorResponse { fields } => { try!(conn.wait_for_ready()); - Err(PgDbError(PostgresDbError::new(fields))) + PostgresDbError::new(fields) } _ => { conn.desynchronized = true; @@ -1251,7 +1252,7 @@ impl<'conn> PostgresStatement<'conn> { DataRow { .. } => {} ErrorResponse { fields } => { try!(conn.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } CommandComplete { tag } => { num = util::parse_update_count(tag); @@ -1357,7 +1358,7 @@ impl<'stmt> PostgresRows<'stmt> { ReadyForQuery { .. } => break, ErrorResponse { fields } => { try!(conn.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } _ => {} } @@ -1381,7 +1382,7 @@ impl<'stmt> PostgresRows<'stmt> { DataRow { row } => self.data.push(row), ErrorResponse { fields } => { try!(conn.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } CopyInResponse { .. } => { try_pg!(conn.write_messages([ @@ -1622,7 +1623,7 @@ impl<'a> PostgresCopyInStatement<'a> { BindComplete => {}, ErrorResponse { fields } => { try!(conn.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } _ => { conn.desynchronized = true; @@ -1692,7 +1693,7 @@ impl<'a> PostgresCopyInStatement<'a> { CommandComplete { tag } => util::parse_update_count(tag), ErrorResponse { fields } => { try!(conn.wait_for_ready()); - return Err(PgDbError(PostgresDbError::new(fields))); + return PostgresDbError::new(fields); } _ => { conn.desynchronized = true;