Skip to content

Commit 3519796

Browse files
committed
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.
1 parent 81fc578 commit 3519796

File tree

10 files changed

+60
-41
lines changed

10 files changed

+60
-41
lines changed

src/error.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@ impl DbErrorNew for DbError {
6666
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
6767
match DbError::new_raw(fields) {
6868
Ok(err) => Err(ConnectError::DbError(err)),
69-
Err(()) => Err(ConnectError::BadResponse),
69+
Err(()) => Err(ConnectError::IoError(::bad_response())),
7070
}
7171
}
7272

7373
fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
7474
match DbError::new_raw(fields) {
7575
Ok(err) => Err(Error::DbError(err)),
76-
Err(()) => Err(Error::BadResponse),
76+
Err(()) => Err(Error::IoError(::bad_response())),
7777
}
7878
}
7979
}
@@ -205,11 +205,9 @@ pub enum ConnectError {
205205
/// The Postgres server does not support SSL encryption.
206206
NoSslSupport,
207207
/// There was an error initializing the SSL session
208-
SslError(Box<error::Error>),
208+
SslError(Box<error::Error+Sync+Send>),
209209
/// There was an error communicating with the server.
210210
IoError(io::Error),
211-
/// The server sent an unexpected response.
212-
BadResponse,
213211
}
214212

215213
impl fmt::Display for ConnectError {
@@ -235,7 +233,6 @@ impl error::Error for ConnectError {
235233
ConnectError::NoSslSupport => "The server does not support SSL",
236234
ConnectError::SslError(_) => "Error initiating SSL session",
237235
ConnectError::IoError(_) => "Error communicating with server",
238-
ConnectError::BadResponse => "The server returned an unexpected response",
239236
}
240237
}
241238

@@ -296,10 +293,8 @@ pub enum Error {
296293
WrongType(Type),
297294
/// An attempt was made to read from a column that does not exist.
298295
InvalidColumn,
299-
/// A value was NULL but converted to a non-nullable Rust type.
300-
WasNull,
301-
/// The server returned an unexpected response.
302-
BadResponse,
296+
/// An error converting between Postgres and Rust types.
297+
Conversion(Box<error::Error+Sync+Send>),
303298
}
304299

305300
impl fmt::Display for Error {
@@ -322,15 +317,15 @@ impl error::Error for Error {
322317
}
323318
Error::WrongType(_) => "Unexpected type",
324319
Error::InvalidColumn => "Invalid column",
325-
Error::WasNull => "The value was NULL",
326-
Error::BadResponse => "The server returned an unexpected response",
320+
Error::Conversion(_) => "An error converting between Postgres and Rust types",
327321
}
328322
}
329323

330324
fn cause(&self) -> Option<&error::Error> {
331325
match *self {
332326
Error::DbError(ref err) => Some(err),
333327
Error::IoError(ref err) => Some(err),
328+
Error::Conversion(ref err) => Some(&**err),
334329
_ => None
335330
}
336331
}

src/io/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ pub trait NegotiateSsl {
2626
///
2727
/// The host portion of the connection parameters is provided for hostname
2828
/// verification.
29-
fn negotiate_ssl(&self, host: &str, stream: Stream) -> Result<Box<StreamWrapper>, Box<Error>>;
29+
fn negotiate_ssl(&self, host: &str, stream: Stream)
30+
-> Result<Box<StreamWrapper>, Box<Error+Sync+Send>>;
3031
}

src/lib.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,11 @@ pub fn cancel_query<T>(params: T, ssl: &SslMode, data: CancelData)
402402
Ok(())
403403
}
404404

405+
fn bad_response() -> std_io::Error {
406+
std_io::Error::new(std_io::ErrorKind::InvalidInput,
407+
"the server returned an unexpected response")
408+
}
409+
405410
/// An enumeration of transaction isolation levels.
406411
///
407412
/// See the [Postgres documentation](http://www.postgresql.org/docs/9.4/static/transaction-iso.html)
@@ -451,7 +456,7 @@ impl IsolationLevel {
451456
} else if raw.eq_ignore_ascii_case("SERIALIZABLE") {
452457
Ok(IsolationLevel::Serializable)
453458
} else {
454-
Err(Error::BadResponse)
459+
Err(Error::IoError(bad_response()))
455460
}
456461
}
457462
}
@@ -548,7 +553,7 @@ impl InnerConnection {
548553
}
549554
ReadyForQuery { .. } => break,
550555
ErrorResponse { fields } => return DbError::new_connect(fields),
551-
_ => return Err(ConnectError::BadResponse),
556+
_ => return Err(ConnectError::IoError(bad_response())),
552557
}
553558
}
554559

@@ -659,13 +664,13 @@ impl InnerConnection {
659664
| AuthenticationGSS
660665
| AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
661666
ErrorResponse { fields } => return DbError::new_connect(fields),
662-
_ => return Err(ConnectError::BadResponse)
667+
_ => return Err(ConnectError::IoError(bad_response()))
663668
}
664669

665670
match try!(self.read_message()) {
666671
AuthenticationOk => Ok(()),
667672
ErrorResponse { fields } => return DbError::new_connect(fields),
668-
_ => return Err(ConnectError::BadResponse)
673+
_ => return Err(ConnectError::IoError(bad_response()))
669674
}
670675
}
671676

@@ -1469,7 +1474,7 @@ impl<'conn> Statement<'conn> {
14691474
}
14701475
_ => {
14711476
conn.desynchronized = true;
1472-
Err(Error::BadResponse)
1477+
Err(Error::IoError(bad_response()))
14731478
}
14741479
}
14751480
}
@@ -1545,7 +1550,7 @@ impl<'conn> Statement<'conn> {
15451550
}
15461551
_ => {
15471552
conn.desynchronized = true;
1548-
return Err(Error::BadResponse);
1553+
return Err(Error::IoError(bad_response()));
15491554
}
15501555
}
15511556
}
@@ -1693,7 +1698,7 @@ fn read_rows(conn: &mut InnerConnection, buf: &mut VecDeque<Vec<Option<Vec<u8>>>
16931698
}
16941699
_ => {
16951700
conn.desynchronized = true;
1696-
return Err(Error::BadResponse);
1701+
return Err(Error::IoError(bad_response()));
16971702
}
16981703
}
16991704
}
@@ -2136,15 +2141,15 @@ impl<'a> CopyInStatement<'a> {
21362141
}
21372142
_ => {
21382143
conn.desynchronized = true;
2139-
return Err(Error::BadResponse);
2144+
return Err(Error::IoError(bad_response()));
21402145
}
21412146
}
21422147

21432148
match try!(conn.read_message()) {
21442149
CopyInResponse { .. } => {}
21452150
_ => {
21462151
conn.desynchronized = true;
2147-
return Err(Error::BadResponse);
2152+
return Err(Error::IoError(bad_response()));
21482153
}
21492154
}
21502155

@@ -2213,7 +2218,7 @@ impl<'a> CopyInStatement<'a> {
22132218
}
22142219
_ => {
22152220
conn.desynchronized = true;
2216-
return Err(Error::BadResponse);
2221+
return Err(Error::IoError(bad_response()));
22172222
}
22182223
};
22192224

src/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ macro_rules! bad_response {
2222
($s:expr) => ({
2323
debug!("Bad response at {}:{}", file!(), line!());
2424
$s.desynchronized = true;
25-
return Err(::Error::BadResponse);
25+
return Err(::Error::IoError(::bad_response()));
2626
})
2727
}

src/priv_io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ pub fn initialize_stream(params: &ConnectParams, ssl: &SslMode)
143143
let host = match params.target {
144144
ConnectTarget::Tcp(ref host) => host,
145145
#[cfg(feature = "unix_socket")]
146-
ConnectTarget::Unix(_) => return Err(ConnectError::BadResponse)
146+
ConnectTarget::Unix(_) => return Err(ConnectError::IoError(::bad_response()))
147147
};
148148

149149
match negotiator.negotiate_ssl(host, socket) {

src/types/mod.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
pub use self::slice::Slice;
33

44
use std::collections::HashMap;
5+
use std::error;
56
use std::fmt;
67
use std::io::prelude::*;
78
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
@@ -514,6 +515,23 @@ impl Other {
514515
}
515516
}
516517

518+
/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
519+
/// implementation that does not support `NULL` values.
520+
#[derive(Debug, Clone, Copy)]
521+
pub struct WasNull;
522+
523+
impl fmt::Display for WasNull {
524+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
525+
fmt.write_str(error::Error::description(self))
526+
}
527+
}
528+
529+
impl error::Error for WasNull {
530+
fn description(&self) -> &str {
531+
"a Postgres value was `NULL`"
532+
}
533+
}
534+
517535
/// A trait for types that can be created from a Postgres value.
518536
///
519537
/// # Types
@@ -566,13 +584,13 @@ pub trait FromSql: Sized {
566584
/// is compatible with the Postgres `Type`.
567585
///
568586
/// The default implementation calls `FromSql::from_sql` when `raw` is
569-
/// `Some` and returns `Err(Error::WasNull)` when `raw` is `None`. It does
570-
/// not typically need to be overridden.
587+
/// `Some` and returns `Err(Error::Conversion(Box::new(WasNull))` when
588+
/// `raw` is `None`. It does not typically need to be overridden.
571589
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
572590
-> Result<Self> {
573591
match raw {
574592
Some(raw) => FromSql::from_sql(ty, raw, ctx),
575-
None => Err(Error::WasNull),
593+
None => Err(Error::Conversion(Box::new(WasNull))),
576594
}
577595
}
578596

@@ -628,7 +646,7 @@ impl FromSql for String {
628646
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<String> {
629647
let mut buf = vec![];
630648
try!(raw.read_to_end(&mut buf));
631-
String::from_utf8(buf).map_err(|_| Error::BadResponse)
649+
String::from_utf8(buf).map_err(|err| Error::Conversion(Box::new(err)))
632650
}
633651

634652
fn accepts(ty: &Type) -> bool {
@@ -680,7 +698,7 @@ impl FromSql for HashMap<String, Option<String>> {
680698
try!(util::read_all(raw, &mut key));
681699
let key = match String::from_utf8(key) {
682700
Ok(key) => key,
683-
Err(_) => return Err(Error::BadResponse),
701+
Err(err) => return Err(Error::Conversion(Box::new(err))),
684702
};
685703

686704
let val_len = try!(raw.read_i32::<BigEndian>());
@@ -691,7 +709,7 @@ impl FromSql for HashMap<String, Option<String>> {
691709
try!(util::read_all(raw, &mut val));
692710
match String::from_utf8(val) {
693711
Ok(val) => Some(val),
694-
Err(_) => return Err(Error::BadResponse),
712+
Err(err) => return Err(Error::Conversion(Box::new(err))),
695713
}
696714
};
697715

src/types/rustc_serialize.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use serialize::json;
2+
use std::error;
23
use std::io::prelude::*;
34
use byteorder::{ReadBytesExt, WriteBytesExt};
45

@@ -10,10 +11,11 @@ impl FromSql for json::Json {
1011
if let Type::Jsonb = *ty {
1112
// We only support version 1 of the jsonb binary format
1213
if try!(raw.read_u8()) != 1 {
13-
return Err(Error::BadResponse);
14+
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
15+
return Err(Error::Conversion(err));
1416
}
1517
}
16-
json::Json::from_reader(raw).map_err(|_| Error::BadResponse)
18+
json::Json::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err)))
1719
}
1820

1921
accepts!(Type::Json, Type::Jsonb);

src/types/serde.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
extern crate serde;
22

3+
use std::error;
34
use std::io::prelude::*;
45
use byteorder::{ReadBytesExt, WriteBytesExt};
56
use self::serde::json::{self, Value};
@@ -12,10 +13,11 @@ impl FromSql for Value {
1213
if let Type::Jsonb = *ty {
1314
// We only support version 1 of the jsonb binary format
1415
if try!(raw.read_u8()) != 1 {
15-
return Err(Error::BadResponse);
16+
let err: Box<error::Error+Sync+Send> = "unsupported JSONB encoding version".into();
17+
return Err(Error::Conversion(err));
1618
}
1719
}
18-
json::de::from_reader(raw).map_err(|_| Error::BadResponse)
20+
json::de::from_reader(raw).map_err(|err| Error::Conversion(Box::new(err)))
1921
}
2022

2123
accepts!(Type::Json, Type::Jsonb);

src/types/uuid.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,14 @@ use std::io::prelude::*;
44

55
use self::uuid::Uuid;
66
use types::{FromSql, ToSql, Type, IsNull, SessionInfo};
7-
use Error;
87
use Result;
98
use util;
109

1110
impl FromSql for Uuid {
1211
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Uuid> {
1312
let mut bytes = [0; 16];
1413
try!(util::read_all(raw, &mut bytes));
15-
match Uuid::from_bytes(&bytes) {
16-
Some(u) => Ok(u),
17-
None => Err(Error::BadResponse),
18-
}
14+
Ok(Uuid::from_bytes(&bytes).unwrap())
1915
}
2016

2117
accepts!(Type::Uuid);

tests/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ fn test_get_was_null() {
507507
let result = or_panic!(stmt.query(&[]));
508508

509509
match result.iter().next().unwrap().get_opt::<usize, i32>(0) {
510-
Err(Error::WasNull) => {}
510+
Err(Error::Conversion(..)) => {}
511511
res => panic!("unexpected result {:?}", res),
512512
};
513513
}

0 commit comments

Comments
 (0)