Restructure errors
WasNull and BadResponse are gone, and Conversion was added. IoError covers the BadResponse case and Conversion is a more general version of WasNull.
This commit is contained in:
parent
81fc578ca6
commit
35197960b2
19
src/error.rs
19
src/error.rs
@ -66,14 +66,14 @@ impl DbErrorNew for DbError {
|
||||
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
|
||||
match DbError::new_raw(fields) {
|
||||
Ok(err) => Err(ConnectError::DbError(err)),
|
||||
Err(()) => Err(ConnectError::BadResponse),
|
||||
Err(()) => Err(ConnectError::IoError(::bad_response())),
|
||||
}
|
||||
}
|
||||
|
||||
fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
|
||||
match DbError::new_raw(fields) {
|
||||
Ok(err) => Err(Error::DbError(err)),
|
||||
Err(()) => Err(Error::BadResponse),
|
||||
Err(()) => Err(Error::IoError(::bad_response())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -205,11 +205,9 @@ pub enum ConnectError {
|
||||
/// The Postgres server does not support SSL encryption.
|
||||
NoSslSupport,
|
||||
/// There was an error initializing the SSL session
|
||||
SslError(Box<error::Error>),
|
||||
SslError(Box<error::Error+Sync+Send>),
|
||||
/// There was an error communicating with the server.
|
||||
IoError(io::Error),
|
||||
/// The server sent an unexpected response.
|
||||
BadResponse,
|
||||
}
|
||||
|
||||
impl fmt::Display for ConnectError {
|
||||
@ -235,7 +233,6 @@ impl error::Error for ConnectError {
|
||||
ConnectError::NoSslSupport => "The server does not support SSL",
|
||||
ConnectError::SslError(_) => "Error initiating SSL session",
|
||||
ConnectError::IoError(_) => "Error communicating with server",
|
||||
ConnectError::BadResponse => "The server returned an unexpected response",
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,10 +293,8 @@ pub enum Error {
|
||||
WrongType(Type),
|
||||
/// An attempt was made to read from a column that does not exist.
|
||||
InvalidColumn,
|
||||
/// A value was NULL but converted to a non-nullable Rust type.
|
||||
WasNull,
|
||||
/// The server returned an unexpected response.
|
||||
BadResponse,
|
||||
/// An error converting between Postgres and Rust types.
|
||||
Conversion(Box<error::Error+Sync+Send>),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
@ -322,8 +317,7 @@ impl error::Error for Error {
|
||||
}
|
||||
Error::WrongType(_) => "Unexpected type",
|
||||
Error::InvalidColumn => "Invalid column",
|
||||
Error::WasNull => "The value was NULL",
|
||||
Error::BadResponse => "The server returned an unexpected response",
|
||||
Error::Conversion(_) => "An error converting between Postgres and Rust types",
|
||||
}
|
||||
}
|
||||
|
||||
@ -331,6 +325,7 @@ impl error::Error for Error {
|
||||
match *self {
|
||||
Error::DbError(ref err) => Some(err),
|
||||
Error::IoError(ref err) => Some(err),
|
||||
Error::Conversion(ref err) => Some(&**err),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
@ -26,5 +26,6 @@ pub trait NegotiateSsl {
|
||||
///
|
||||
/// The host portion of the connection parameters is provided for hostname
|
||||
/// verification.
|
||||
fn negotiate_ssl(&self, host: &str, stream: Stream) -> Result<Box<StreamWrapper>, Box<Error>>;
|
||||
fn negotiate_ssl(&self, host: &str, stream: Stream)
|
||||
-> Result<Box<StreamWrapper>, Box<Error+Sync+Send>>;
|
||||
}
|
||||
|
25
src/lib.rs
25
src/lib.rs
@ -402,6 +402,11 @@ pub fn cancel_query<T>(params: T, ssl: &SslMode, data: CancelData)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bad_response() -> std_io::Error {
|
||||
std_io::Error::new(std_io::ErrorKind::InvalidInput,
|
||||
"the server returned an unexpected response")
|
||||
}
|
||||
|
||||
/// An enumeration of transaction isolation levels.
|
||||
///
|
||||
/// See the [Postgres documentation](http://www.postgresql.org/docs/9.4/static/transaction-iso.html)
|
||||
@ -451,7 +456,7 @@ impl IsolationLevel {
|
||||
} else if raw.eq_ignore_ascii_case("SERIALIZABLE") {
|
||||
Ok(IsolationLevel::Serializable)
|
||||
} else {
|
||||
Err(Error::BadResponse)
|
||||
Err(Error::IoError(bad_response()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -548,7 +553,7 @@ impl InnerConnection {
|
||||
}
|
||||
ReadyForQuery { .. } => break,
|
||||
ErrorResponse { fields } => return DbError::new_connect(fields),
|
||||
_ => return Err(ConnectError::BadResponse),
|
||||
_ => return Err(ConnectError::IoError(bad_response())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -659,13 +664,13 @@ impl InnerConnection {
|
||||
| AuthenticationGSS
|
||||
| AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
|
||||
ErrorResponse { fields } => return DbError::new_connect(fields),
|
||||
_ => return Err(ConnectError::BadResponse)
|
||||
_ => return Err(ConnectError::IoError(bad_response()))
|
||||
}
|
||||
|
||||
match try!(self.read_message()) {
|
||||
AuthenticationOk => Ok(()),
|
||||
ErrorResponse { fields } => return DbError::new_connect(fields),
|
||||
_ => return Err(ConnectError::BadResponse)
|
||||
_ => return Err(ConnectError::IoError(bad_response()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1469,7 +1474,7 @@ impl<'conn> Statement<'conn> {
|
||||
}
|
||||
_ => {
|
||||
conn.desynchronized = true;
|
||||
Err(Error::BadResponse)
|
||||
Err(Error::IoError(bad_response()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1545,7 +1550,7 @@ impl<'conn> Statement<'conn> {
|
||||
}
|
||||
_ => {
|
||||
conn.desynchronized = true;
|
||||
return Err(Error::BadResponse);
|
||||
return Err(Error::IoError(bad_response()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1693,7 +1698,7 @@ fn read_rows(conn: &mut InnerConnection, buf: &mut VecDeque<Vec<Option<Vec<u8>>>
|
||||
}
|
||||
_ => {
|
||||
conn.desynchronized = true;
|
||||
return Err(Error::BadResponse);
|
||||
return Err(Error::IoError(bad_response()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2136,7 +2141,7 @@ impl<'a> CopyInStatement<'a> {
|
||||
}
|
||||
_ => {
|
||||
conn.desynchronized = true;
|
||||
return Err(Error::BadResponse);
|
||||
return Err(Error::IoError(bad_response()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2144,7 +2149,7 @@ impl<'a> CopyInStatement<'a> {
|
||||
CopyInResponse { .. } => {}
|
||||
_ => {
|
||||
conn.desynchronized = true;
|
||||
return Err(Error::BadResponse);
|
||||
return Err(Error::IoError(bad_response()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2213,7 +2218,7 @@ impl<'a> CopyInStatement<'a> {
|
||||
}
|
||||
_ => {
|
||||
conn.desynchronized = true;
|
||||
return Err(Error::BadResponse);
|
||||
return Err(Error::IoError(bad_response()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,6 @@ macro_rules! bad_response {
|
||||
($s:expr) => ({
|
||||
debug!("Bad response at {}:{}", file!(), line!());
|
||||
$s.desynchronized = true;
|
||||
return Err(::Error::BadResponse);
|
||||
return Err(::Error::IoError(::bad_response()));
|
||||
})
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ pub fn initialize_stream(params: &ConnectParams, ssl: &SslMode)
|
||||
let host = match params.target {
|
||||
ConnectTarget::Tcp(ref host) => host,
|
||||
#[cfg(feature = "unix_socket")]
|
||||
ConnectTarget::Unix(_) => return Err(ConnectError::BadResponse)
|
||||
ConnectTarget::Unix(_) => return Err(ConnectError::IoError(::bad_response()))
|
||||
};
|
||||
|
||||
match negotiator.negotiate_ssl(host, socket) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
pub use self::slice::Slice;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io::prelude::*;
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
||||
@ -514,6 +515,23 @@ impl Other {
|
||||
}
|
||||
}
|
||||
|
||||
/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
|
||||
/// implementation that does not support `NULL` values.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct WasNull;
|
||||
|
||||
impl fmt::Display for WasNull {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.write_str(error::Error::description(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for WasNull {
|
||||
fn description(&self) -> &str {
|
||||
"a Postgres value was `NULL`"
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types that can be created from a Postgres value.
|
||||
///
|
||||
/// # Types
|
||||
@ -566,13 +584,13 @@ pub trait FromSql: Sized {
|
||||
/// is compatible with the Postgres `Type`.
|
||||
///
|
||||
/// The default implementation calls `FromSql::from_sql` when `raw` is
|
||||
/// `Some` and returns `Err(Error::WasNull)` when `raw` is `None`. It does
|
||||
/// not typically need to be overridden.
|
||||
/// `Some` and returns `Err(Error::Conversion(Box::new(WasNull))` when
|
||||
/// `raw` is `None`. It does not typically need to be overridden.
|
||||
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
|
||||
-> Result<Self> {
|
||||
match raw {
|
||||
Some(raw) => FromSql::from_sql(ty, raw, ctx),
|
||||
None => Err(Error::WasNull),
|
||||
None => Err(Error::Conversion(Box::new(WasNull))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -628,7 +646,7 @@ 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(|_| Error::BadResponse)
|
||||
String::from_utf8(buf).map_err(|err| Error::Conversion(Box::new(err)))
|
||||
}
|
||||
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
@ -680,7 +698,7 @@ impl FromSql for HashMap<String, Option<String>> {
|
||||
try!(util::read_all(raw, &mut key));
|
||||
let key = match String::from_utf8(key) {
|
||||
Ok(key) => key,
|
||||
Err(_) => return Err(Error::BadResponse),
|
||||
Err(err) => return Err(Error::Conversion(Box::new(err))),
|
||||
};
|
||||
|
||||
let val_len = try!(raw.read_i32::<BigEndian>());
|
||||
@ -691,7 +709,7 @@ impl FromSql for HashMap<String, Option<String>> {
|
||||
try!(util::read_all(raw, &mut val));
|
||||
match String::from_utf8(val) {
|
||||
Ok(val) => Some(val),
|
||||
Err(_) => return Err(Error::BadResponse),
|
||||
Err(err) => return Err(Error::Conversion(Box::new(err))),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use serialize::json;
|
||||
use std::error;
|
||||
use std::io::prelude::*;
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
|
||||
@ -10,10 +11,11 @@ impl FromSql for json::Json {
|
||||
if let Type::Jsonb = *ty {
|
||||
// We only support version 1 of the jsonb binary format
|
||||
if try!(raw.read_u8()) != 1 {
|
||||
return Err(Error::BadResponse);
|
||||
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
|
||||
return Err(Error::Conversion(err));
|
||||
}
|
||||
}
|
||||
json::Json::from_reader(raw).map_err(|_| Error::BadResponse)
|
||||
json::Json::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err)))
|
||||
}
|
||||
|
||||
accepts!(Type::Json, Type::Jsonb);
|
||||
|
@ -1,5 +1,6 @@
|
||||
extern crate serde;
|
||||
|
||||
use std::error;
|
||||
use std::io::prelude::*;
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
use self::serde::json::{self, Value};
|
||||
@ -12,10 +13,11 @@ impl FromSql for Value {
|
||||
if let Type::Jsonb = *ty {
|
||||
// We only support version 1 of the jsonb binary format
|
||||
if try!(raw.read_u8()) != 1 {
|
||||
return Err(Error::BadResponse);
|
||||
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
|
||||
return Err(Error::Conversion(err));
|
||||
}
|
||||
}
|
||||
json::de::from_reader(raw).map_err(|_| Error::BadResponse)
|
||||
json::de::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err)))
|
||||
}
|
||||
|
||||
accepts!(Type::Json, Type::Jsonb);
|
||||
|
@ -4,7 +4,6 @@ use std::io::prelude::*;
|
||||
|
||||
use self::uuid::Uuid;
|
||||
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
|
||||
use Error;
|
||||
use Result;
|
||||
use util;
|
||||
|
||||
@ -12,10 +11,7 @@ impl FromSql for Uuid {
|
||||
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Uuid> {
|
||||
let mut bytes = [0; 16];
|
||||
try!(util::read_all(raw, &mut bytes));
|
||||
match Uuid::from_bytes(&bytes) {
|
||||
Some(u) => Ok(u),
|
||||
None => Err(Error::BadResponse),
|
||||
}
|
||||
Ok(Uuid::from_bytes(&bytes).unwrap())
|
||||
}
|
||||
|
||||
accepts!(Type::Uuid);
|
||||
|
@ -507,7 +507,7 @@ fn test_get_was_null() {
|
||||
let result = or_panic!(stmt.query(&[]));
|
||||
|
||||
match result.iter().next().unwrap().get_opt::<usize, i32>(0) {
|
||||
Err(Error::WasNull) => {}
|
||||
Err(Error::Conversion(..)) => {}
|
||||
res => panic!("unexpected result {:?}", res),
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user