Unify error types for postgres

This commit is contained in:
Steven Fackler 2017-07-16 18:13:49 -07:00
parent 7069c57660
commit 15a1b791c4
10 changed files with 268 additions and 226 deletions

View File

@ -7,60 +7,106 @@ use std::error;
// FIXME
pub use postgres_shared::error::*;
/// An error encountered when communicating with the Postgres server.
#[derive(Debug)]
pub enum Error {
/// An error reported by the Postgres server.
Db(Box<DbError>),
/// An error communicating with the Postgres server.
pub(crate) enum ErrorKind {
ConnectParams(Box<error::Error + Sync + Send>),
Tls(Box<error::Error + Sync + Send>),
Db(DbError),
Io(io::Error),
/// An error converting between Postgres and Rust types.
Conversion(Box<error::Error + Sync + Send>),
}
/// An error communicating with the Postgres server.
#[derive(Debug)]
pub struct Error(pub(crate) Box<ErrorKind>);
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(error::Error::description(self))?;
match *self {
Error::Db(ref err) => write!(fmt, ": {}", err),
Error::Io(ref err) => write!(fmt, ": {}", err),
Error::Conversion(ref err) => write!(fmt, ": {}", err),
match *self.0 {
ErrorKind::ConnectParams(ref err) => write!(fmt, ": {}", err),
ErrorKind::Tls(ref err) => write!(fmt, ": {}", err),
ErrorKind::Db(ref err) => write!(fmt, ": {}", err),
ErrorKind::Io(ref err) => write!(fmt, ": {}", err),
ErrorKind::Conversion(ref err) => write!(fmt, ": {}", err),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::Db(_) => "Error reported by Postgres",
Error::Io(_) => "Error communicating with the server",
Error::Conversion(_) => "Error converting between Postgres and Rust types",
match *self.0 {
ErrorKind::ConnectParams(_) => "invalid connection parameters",
ErrorKind::Tls(_) => "TLS handshake error",
ErrorKind::Db(_) => "database error",
ErrorKind::Io(_) => "IO error",
ErrorKind::Conversion(_) => "type conversion error",
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Db(ref err) => Some(&**err),
Error::Io(ref err) => Some(err),
Error::Conversion(ref err) => Some(&**err),
match *self.0 {
ErrorKind::ConnectParams(ref err) => Some(&**err),
ErrorKind::Tls(ref err) => Some(&**err),
ErrorKind::Db(ref err) => Some(err),
ErrorKind::Io(ref err) => Some(err),
ErrorKind::Conversion(ref err) => Some(&**err),
}
}
}
impl From<DbError> for Error {
fn from(err: DbError) -> Error {
Error::Db(Box::new(err))
impl Error {
/// Returns the SQLSTATE error code associated with this error if it is a DB
/// error.
pub fn code(&self) -> Option<&SqlState> {
self.as_db().map(|e| &e.code)
}
/// Returns the inner error if this is a connection parameter error.
pub fn as_connection(&self) -> Option<&(error::Error + 'static + Sync + Send)> {
match *self.0 {
ErrorKind::ConnectParams(ref err) => Some(&**err),
_ => None,
}
}
/// Returns the `DbError` associated with this error if it is a DB error.
pub fn as_db(&self) -> Option<&DbError> {
match *self.0 {
ErrorKind::Db(ref err) => Some(err),
_ => None
}
}
/// Returns the inner error if this is a conversion error.
pub fn as_conversion(&self) -> Option<&(error::Error + 'static + Sync + Send)> {
match *self.0 {
ErrorKind::Conversion(ref err) => Some(&**err),
_ => None,
}
}
/// Returns the inner `io::Error` associated with this error if it is an IO
/// error.
pub fn as_io(&self) -> Option<&io::Error> {
match *self.0 {
ErrorKind::Io(ref err) => Some(err),
_ => None,
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::Io(err)
Error(Box::new(ErrorKind::Io(err)))
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> io::Error {
io::Error::new(io::ErrorKind::Other, err)
match *err.0 {
ErrorKind::Io(e) => e,
_ => io::Error::new(io::ErrorKind::Other, err),
}
}
}

View File

@ -93,7 +93,7 @@ use postgres_protocol::message::backend::{self, ErrorFields};
use postgres_protocol::message::frontend;
use postgres_shared::rows::RowData;
use error::{Error, ConnectError, DbError, UNDEFINED_COLUMN, UNDEFINED_TABLE};
use error::{ErrorKind, DbError, UNDEFINED_COLUMN, UNDEFINED_TABLE};
use tls::TlsHandshake;
use notification::{Notifications, Notification};
use params::{IntoConnectParams, User};
@ -105,6 +105,8 @@ use types::{IsNull, Kind, Type, Oid, ToSql, FromSql, Field, OID, NAME, CHAR};
#[doc(inline)]
pub use postgres_shared::CancelData;
#[doc(inline)]
pub use error::Error;
#[macro_use]
mod macros;
@ -178,17 +180,13 @@ impl HandleNotice for LoggingNoticeHandler {
/// });
/// postgres::cancel_query(url, TlsMode::None, &cancel_data).unwrap();
/// ```
pub fn cancel_query<T>(
params: T,
tls: TlsMode,
data: &CancelData,
) -> result::Result<(), ConnectError>
pub fn cancel_query<T>(params: T, tls: TlsMode, data: &CancelData) -> Result<()>
where
T: IntoConnectParams,
{
let params = params.into_connect_params().map_err(
ConnectError::ConnectParams,
)?;
let params = params.into_connect_params().map_err(|e| {
Error(Box::new(ErrorKind::ConnectParams(e)))
})?;
let mut socket = priv_io::initialize_stream(&params, tls)?;
let mut buf = vec![];
@ -257,21 +255,21 @@ impl Drop for InnerConnection {
}
impl InnerConnection {
fn connect<T>(params: T, tls: TlsMode) -> result::Result<InnerConnection, ConnectError>
fn connect<T>(params: T, tls: TlsMode) -> Result<InnerConnection>
where
T: IntoConnectParams,
{
let params = params.into_connect_params().map_err(
ConnectError::ConnectParams,
)?;
let params = params.into_connect_params().map_err(|e| {
Error(Box::new(ErrorKind::ConnectParams(e)))
})?;
let stream = priv_io::initialize_stream(&params, tls)?;
let user = match params.user() {
Some(user) => user,
None => {
return Err(ConnectError::ConnectParams(
return Err(Error(Box::new(ErrorKind::ConnectParams(
"User missing from connection parameters".into(),
));
))));
}
};
@ -322,9 +320,9 @@ impl InnerConnection {
}
backend::Message::ReadyForQuery(_) => break,
backend::Message::ErrorResponse(body) => {
return Err(connect_err(&mut body.fields()));
return Err(err(&mut body.fields()));
}
_ => return Err(ConnectError::Io(bad_response())),
_ => return Err(bad_response().into()),
}
}
@ -411,12 +409,14 @@ impl InnerConnection {
}
}
fn handle_auth(&mut self, user: &User) -> result::Result<(), ConnectError> {
fn handle_auth(&mut self, user: &User) -> Result<()> {
match self.read_message()? {
backend::Message::AuthenticationOk => return Ok(()),
backend::Message::AuthenticationCleartextPassword => {
let pass = user.password().ok_or_else(|| {
ConnectError::ConnectParams("a password was requested but not provided".into())
Error(Box::new(ErrorKind::ConnectParams(
"a password was requested but not provided".into(),
)))
})?;
self.stream.write_message(
|buf| frontend::password_message(pass, buf),
@ -425,7 +425,9 @@ impl InnerConnection {
}
backend::Message::AuthenticationMd5Password(body) => {
let pass = user.password().ok_or_else(|| {
ConnectError::ConnectParams("a password was requested but not provided".into())
Error(Box::new(ErrorKind::ConnectParams(
"a password was requested but not provided".into(),
)))
})?;
let output =
authentication::md5_hash(user.name().as_bytes(), pass.as_bytes(), body.salt());
@ -440,14 +442,16 @@ impl InnerConnection {
.filter(|m| *m == sasl::SCRAM_SHA_256)
.count()? == 0
{
return Err(ConnectError::Io(io::Error::new(
return Err(io::Error::new(
io::ErrorKind::Other,
"unsupported authentication",
)));
).into());
}
let pass = user.password().ok_or_else(|| {
ConnectError::ConnectParams("a password was requested but not provided".into())
Error(Box::new(ErrorKind::ConnectParams(
"a password was requested but not provided".into(),
)))
})?;
let mut scram = ScramSha256::new(pass.as_bytes())?;
@ -460,9 +464,9 @@ impl InnerConnection {
let body = match self.read_message()? {
backend::Message::AuthenticationSaslContinue(body) => body,
backend::Message::ErrorResponse(body) => {
return Err(connect_err(&mut body.fields()))
return Err(err(&mut body.fields()))
}
_ => return Err(ConnectError::Io(bad_response())),
_ => return Err(bad_response().into()),
};
scram.update(body.data())?;
@ -475,9 +479,9 @@ impl InnerConnection {
let body = match self.read_message()? {
backend::Message::AuthenticationSaslFinal(body) => body,
backend::Message::ErrorResponse(body) => {
return Err(connect_err(&mut body.fields()))
return Err(err(&mut body.fields()))
}
_ => return Err(ConnectError::Io(bad_response())),
_ => return Err(bad_response().into()),
};
scram.finish(body.data())?;
@ -486,19 +490,19 @@ impl InnerConnection {
backend::Message::AuthenticationScmCredential |
backend::Message::AuthenticationGss |
backend::Message::AuthenticationSspi => {
return Err(ConnectError::Io(io::Error::new(
return Err(io::Error::new(
io::ErrorKind::Other,
"unsupported authentication",
)))
).into())
}
backend::Message::ErrorResponse(body) => return Err(connect_err(&mut body.fields())),
_ => return Err(ConnectError::Io(bad_response())),
backend::Message::ErrorResponse(body) => return Err(err(&mut body.fields())),
_ => return Err(bad_response().into()),
}
match self.read_message()? {
backend::Message::AuthenticationOk => Ok(()),
backend::Message::ErrorResponse(body) => Err(connect_err(&mut body.fields())),
_ => Err(ConnectError::Io(bad_response())),
backend::Message::ErrorResponse(body) => Err(err(&mut body.fields())),
_ => Err(bad_response().into()),
}
}
@ -601,15 +605,17 @@ impl InnerConnection {
break;
}
}
return Err(Error::Io(io::Error::new(
io::ErrorKind::InvalidInput,
"COPY queries cannot be directly \
return Err(
io::Error::new(
io::ErrorKind::InvalidInput,
"COPY queries cannot be directly \
executed",
)));
).into(),
);
}
_ => {
self.desynchronized = true;
return Err(Error::Io(bad_response()));
return Err(bad_response().into());
}
}
}
@ -655,8 +661,10 @@ impl InnerConnection {
});
match r {
Ok(()) => {}
Err(frontend::BindError::Conversion(e)) => return Err(Error::Conversion(e)),
Err(frontend::BindError::Serialization(e)) => return Err(Error::Io(e)),
Err(frontend::BindError::Conversion(e)) => {
return Err(Error(Box::new(ErrorKind::Conversion(e))))
}
Err(frontend::BindError::Serialization(e)) => return Err(e.into()),
}
}
@ -676,7 +684,7 @@ impl InnerConnection {
}
_ => {
self.desynchronized = true;
Err(Error::Io(bad_response()))
Err(bad_response().into())
}
}
}
@ -771,7 +779,7 @@ impl InnerConnection {
) {
Ok(..) => {}
// Range types weren't added until Postgres 9.2, so pg_range may not exist
Err(Error::Db(ref e)) if e.code == UNDEFINED_TABLE => {
Err(ref e) if e.code() == Some(&UNDEFINED_TABLE) => {
self.raw_prepare(
TYPEINFO_QUERY,
"SELECT t.typname, t.typtype, t.typelem, NULL::OID, \
@ -799,27 +807,29 @@ impl InnerConnection {
let get_raw = |i: usize| row.as_ref().and_then(|r| r.get(i));
let (name, type_, elem_oid, rngsubtype, basetype, schema, relid) = {
let name = String::from_sql_nullable(&NAME, get_raw(0)).map_err(
Error::Conversion,
)?;
let type_ = i8::from_sql_nullable(&CHAR, get_raw(1)).map_err(
Error::Conversion,
)?;
let elem_oid = Oid::from_sql_nullable(&OID, get_raw(2)).map_err(
Error::Conversion,
)?;
let name = String::from_sql_nullable(&NAME, get_raw(0)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
let type_ = i8::from_sql_nullable(&CHAR, get_raw(1)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
let elem_oid = Oid::from_sql_nullable(&OID, get_raw(2)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
let rngsubtype = Option::<Oid>::from_sql_nullable(&OID, get_raw(3)).map_err(
Error::Conversion,
)?;
let basetype = Oid::from_sql_nullable(&OID, get_raw(4)).map_err(
Error::Conversion,
)?;
let schema = String::from_sql_nullable(&NAME, get_raw(5)).map_err(
Error::Conversion,
)?;
let relid = Oid::from_sql_nullable(&OID, get_raw(6)).map_err(
Error::Conversion,
|e| {
Error(Box::new(ErrorKind::Conversion(e)))
},
)?;
let basetype = Oid::from_sql_nullable(&OID, get_raw(4)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
let schema = String::from_sql_nullable(&NAME, get_raw(5)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
let relid = Oid::from_sql_nullable(&OID, get_raw(6)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
(name, type_, elem_oid, rngsubtype, basetype, schema, relid)
};
@ -857,7 +867,7 @@ impl InnerConnection {
) {
Ok(..) => {}
// Postgres 9.0 doesn't have enumsortorder
Err(Error::Db(ref e)) if e.code == UNDEFINED_COLUMN => {
Err(ref e) if e.code() == Some(&UNDEFINED_COLUMN) => {
self.raw_prepare(
TYPEINFO_ENUM_QUERY,
"SELECT enumlabel \
@ -887,9 +897,9 @@ impl InnerConnection {
let mut variants = vec![];
for row in rows {
variants.push(String::from_sql_nullable(&NAME, row.get(0)).map_err(
Error::Conversion,
)?);
variants.push(String::from_sql_nullable(&NAME, row.get(0)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?);
}
Ok(variants)
@ -929,12 +939,12 @@ impl InnerConnection {
let mut fields = vec![];
for row in rows {
let (name, type_) = {
let name = String::from_sql_nullable(&NAME, row.get(0)).map_err(
Error::Conversion,
)?;
let type_ = Oid::from_sql_nullable(&OID, row.get(1)).map_err(
Error::Conversion,
)?;
let name = String::from_sql_nullable(&NAME, row.get(0)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
let type_ = Oid::from_sql_nullable(&OID, row.get(1)).map_err(|e| {
Error(Box::new(ErrorKind::Conversion(e)))
})?;
(name, type_)
};
let type_ = self.get_type(type_)?;
@ -1081,7 +1091,7 @@ impl Connection {
/// let conn = Connection::connect(params, TlsMode::None).unwrap();
/// # }
/// ```
pub fn connect<T>(params: T, tls: TlsMode) -> result::Result<Connection, ConnectError>
pub fn connect<T>(params: T, tls: TlsMode) -> Result<Connection>
where
T: IntoConnectParams,
{
@ -1449,16 +1459,9 @@ impl<'a> GenericConnection for Transaction<'a> {
}
}
fn connect_err(fields: &mut ErrorFields) -> ConnectError {
match DbError::new(fields) {
Ok(err) => ConnectError::Db(Box::new(err)),
Err(err) => ConnectError::Io(err),
}
}
fn err(fields: &mut ErrorFields) -> Error {
match DbError::new(fields) {
Ok(err) => Error::Db(Box::new(err)),
Err(err) => Error::Io(err),
Ok(err) => Error(Box::new(ErrorKind::Db(err))),
Err(err) => err.into(),
}
}

View File

@ -13,7 +13,7 @@ macro_rules! try_desync {
macro_rules! check_desync {
($e:expr) => ({
if $e.is_desynchronized() {
return Err(::error::Error::Io(::desynchronized()));
return Err(::desynchronized().into());
}
})
}
@ -22,7 +22,7 @@ macro_rules! bad_response {
($s:expr) => ({
debug!("Bad response at {}:{}", file!(), line!());
$s.desynchronized = true;
return Err(::error::Error::Io(::bad_response()));
return Err(::bad_response().into());
})
}

View File

@ -99,7 +99,7 @@ impl<'a> FallibleIterator for Iter<'a> {
}
if conn.is_desynchronized() {
return Err(Error::Io(desynchronized()));
return Err(desynchronized().into());
}
match conn.read_message_with_notification_nonblocking() {
@ -111,7 +111,7 @@ impl<'a> FallibleIterator for Iter<'a> {
}))
}
Ok(None) => Ok(None),
Err(err) => Err(Error::Io(err)),
Err(err) => Err(err.into()),
_ => unreachable!(),
}
}
@ -138,7 +138,7 @@ impl<'a> FallibleIterator for BlockingIter<'a> {
}
if conn.is_desynchronized() {
return Err(Error::Io(desynchronized()));
return Err(desynchronized().into());
}
match conn.read_message_with_notification() {
@ -149,7 +149,7 @@ impl<'a> FallibleIterator for BlockingIter<'a> {
payload: body.message()?.to_owned(),
}))
}
Err(err) => Err(Error::Io(err)),
Err(err) => Err(err.into()),
_ => unreachable!(),
}
}
@ -174,7 +174,7 @@ impl<'a> FallibleIterator for TimeoutIter<'a> {
}
if conn.is_desynchronized() {
return Err(Error::Io(desynchronized()));
return Err(desynchronized().into());
}
match conn.read_message_with_notification_timeout(self.timeout) {
@ -186,7 +186,7 @@ impl<'a> FallibleIterator for TimeoutIter<'a> {
}))
}
Ok(None) => Ok(None),
Err(err) => Err(Error::Io(err)),
Err(err) => Err(err.into()),
_ => unreachable!(),
}
}

View File

@ -2,6 +2,7 @@ use std::io::{self, BufWriter, Read, Write};
use std::fmt;
use std::net::TcpStream;
use std::time::Duration;
use std::result;
use bytes::{BufMut, BytesMut};
#[cfg(unix)]
use std::os::unix::net::UnixStream;
@ -12,8 +13,8 @@ use std::os::windows::io::{AsRawSocket, RawSocket};
use postgres_protocol::message::frontend;
use postgres_protocol::message::backend;
use TlsMode;
use error::ConnectError;
use {Error, Result, TlsMode};
use error::ErrorKind;
use tls::TlsStream;
use params::{ConnectParams, Host};
@ -38,9 +39,9 @@ impl MessageStream {
self.stream.get_ref()
}
pub fn write_message<F, E>(&mut self, f: F) -> Result<(), E>
pub fn write_message<F, E>(&mut self, f: F) -> result::Result<(), E>
where
F: FnOnce(&mut Vec<u8>) -> Result<(), E>,
F: FnOnce(&mut Vec<u8>) -> result::Result<(), E>,
E: From<io::Error>,
{
self.out_buf.clear();
@ -229,7 +230,7 @@ impl Write for InternalStream {
}
}
fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
fn open_socket(params: &ConnectParams) -> Result<InternalStream> {
let port = params.port();
match *params.host() {
Host::Tcp(ref host) => {
@ -244,18 +245,17 @@ fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
}
#[cfg(not(unix))]
Host::Unix(..) => {
Err(ConnectError::Io(io::Error::new(
io::ErrorKind::InvalidInput,
"unix sockets are not supported on this system",
)))
Err(
io::Error::new(
io::ErrorKind::InvalidInput,
"unix sockets are not supported on this system",
).into(),
)
}
}
}
pub fn initialize_stream(
params: &ConnectParams,
tls: TlsMode,
) -> Result<Box<TlsStream>, ConnectError> {
pub fn initialize_stream(params: &ConnectParams, tls: TlsMode) -> Result<Box<TlsStream>> {
let mut socket = Stream(open_socket(params)?);
let (tls_required, handshaker) = match tls {
@ -273,7 +273,9 @@ pub fn initialize_stream(
socket.read_exact(&mut b)?;
if b[0] == b'N' {
if tls_required {
return Err(ConnectError::Tls("the server does not support TLS".into()));
return Err(Error(Box::new(
ErrorKind::Tls("the server does not support TLS".into()),
)));
} else {
return Ok(Box::new(socket));
}
@ -282,10 +284,10 @@ pub fn initialize_stream(
let host = match *params.host() {
Host::Tcp(ref host) => host,
// Postgres doesn't support TLS over unix sockets
Host::Unix(_) => return Err(ConnectError::Io(::bad_response())),
Host::Unix(_) => return Err(::bad_response().into()),
};
handshaker.tls_handshake(host, socket).map_err(
ConnectError::Tls,
)
handshaker.tls_handshake(host, socket).map_err(|e| {
Error(Box::new(ErrorKind::Tls(e)))
})
}

View File

@ -11,11 +11,11 @@ use std::ops::Deref;
use std::slice;
use std::sync::Arc;
use {Result, StatementInfo};
use {Error, Result, StatementInfo};
use transaction::Transaction;
use types::{FromSql, WrongType};
use stmt::{Statement, Column};
use error::Error;
use error::ErrorKind;
enum MaybeOwned<'a, T: 'a> {
Borrowed(&'a T),
@ -229,10 +229,12 @@ impl<'a> Row<'a> {
let ty = self.stmt_info.columns[idx].type_();
if !<T as FromSql>::accepts(ty) {
return Some(Err(Error::Conversion(Box::new(WrongType::new(ty.clone())))));
return Some(Err(Error(Box::new(
ErrorKind::Conversion(Box::new(WrongType::new(ty.clone()))),
))));
}
let value = FromSql::from_sql_nullable(ty, self.data.get(idx));
Some(value.map_err(Error::Conversion))
Some(value.map_err(|e| Error(Box::new(ErrorKind::Conversion(e)))))
}
/// Retrieves the specified field as a raw buffer of Postgres data.

View File

@ -9,7 +9,6 @@ use std::sync::Arc;
use postgres_protocol::message::{backend, frontend};
use postgres_shared::rows::RowData;
use error::Error;
use types::{Type, ToSql};
use rows::{Rows, LazyRows};
use transaction::Transaction;
@ -182,7 +181,7 @@ impl<'conn> Statement<'conn> {
}
_ => {
conn.desynchronized = true;
return Err(Error::Io(bad_response()));
return Err(bad_response().into());
}
}
}
@ -320,12 +319,12 @@ impl<'conn> Statement<'conn> {
_ => {
loop {
if let backend::Message::ReadyForQuery(_) = conn.read_message()? {
return Err(Error::Io(io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_in` on a \
non-`COPY FROM STDIN` \
statement",
)));
return Err(
io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_in` on a non-`COPY FROM STDIN` statement",
).into(),
);
}
}
}
@ -362,11 +361,11 @@ impl<'conn> Statement<'conn> {
}
_ => {
conn.desynchronized = true;
return Err(Error::Io(bad_response()));
return Err(bad_response().into());
}
}
conn.wait_for_ready()?;
return Err(Error::Io(err));
return Err(err.into());
}
}
}
@ -387,7 +386,7 @@ impl<'conn> Statement<'conn> {
}
_ => {
conn.desynchronized = true;
return Err(Error::Io(bad_response()));
return Err(bad_response().into());
}
};
@ -450,15 +449,16 @@ impl<'conn> Statement<'conn> {
}
_ => {
conn.desynchronized = true;
return Err(Error::Io(bad_response()));
return Err(bad_response().into());
}
}
conn.wait_for_ready()?;
return Err(Error::Io(io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_out` on a non-`COPY TO \
STDOUT` statement",
)));
return Err(
io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_out` on a non-`COPY TO STDOUT` statement",
).into(),
);
}
backend::Message::ErrorResponse(body) => {
conn.wait_for_ready()?;
@ -467,11 +467,12 @@ impl<'conn> Statement<'conn> {
_ => {
loop {
if let backend::Message::ReadyForQuery(_) = conn.read_message()? {
return Err(Error::Io(io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_out` on a \
non-`COPY TO STDOUT` statement",
)));
return Err(
io::Error::new(
io::ErrorKind::InvalidInput,
"called `copy_out` on a non-`COPY TO STDOUT` statement",
).into(),
);
}
}
}
@ -495,7 +496,7 @@ impl<'conn> Statement<'conn> {
if let backend::Message::ReadyForQuery(_) =
conn.read_message()?
{
return Err(Error::Io(e));
return Err(e.into());
}
}
}
@ -517,7 +518,7 @@ impl<'conn> Statement<'conn> {
_ => {
loop {
if let backend::Message::ReadyForQuery(_) = conn.read_message()? {
return Err(Error::Io(bad_response()));
return Err(bad_response().into());
}
}
}

View File

@ -5,7 +5,6 @@ use std::fmt;
use std::ascii::AsciiExt;
use {bad_response, Result, Connection};
use error::Error;
use rows::Rows;
use stmt::Statement;
use types::ToSql;
@ -42,7 +41,7 @@ impl IsolationLevel {
} else if raw.eq_ignore_ascii_case("SERIALIZABLE") {
Ok(IsolationLevel::Serializable)
} else {
Err(Error::Io(bad_response()))
Err(bad_response().into())
}
}

View File

@ -12,7 +12,7 @@ extern crate native_tls;
use fallible_iterator::FallibleIterator;
use postgres::{HandleNotice, Connection, GenericConnection, TlsMode};
use postgres::transaction::{self, IsolationLevel};
use postgres::error::{Error, ConnectError, DbError, SYNTAX_ERROR, QUERY_CANCELED, UNDEFINED_TABLE,
use postgres::error::{DbError, SYNTAX_ERROR, QUERY_CANCELED, UNDEFINED_TABLE,
INVALID_CATALOG_NAME, INVALID_PASSWORD, CARDINALITY_VIOLATION};
use postgres::types::{Oid, Type, Kind, WrongType, INT4, VARCHAR, FLOAT8};
use postgres::error::ErrorPosition::Normal;
@ -56,18 +56,17 @@ fn test_prepare_err() {
"postgres://postgres@localhost:5433",
TlsMode::None,
));
let stmt = conn.prepare("invalid sql database");
match stmt {
Err(Error::Db(ref e)) if e.code == SYNTAX_ERROR && e.position == Some(Normal(1)) => {}
Err(e) => panic!("Unexpected result {:?}", e),
_ => panic!("Unexpected result"),
let err = conn.prepare("invalid sql database").unwrap_err();
match err.as_db() {
Some(e) if e.code == SYNTAX_ERROR && e.position == Some(Normal(1)) => {}
_ => panic!("Unexpected result {:?}", err),
}
}
#[test]
fn test_unknown_database() {
match Connection::connect("postgres://postgres@localhost:5433/asdf", TlsMode::None) {
Err(ConnectError::Db(ref e)) if e.code == INVALID_CATALOG_NAME => {}
Err(ref e) if e.code() == Some(&INVALID_CATALOG_NAME) => {}
Err(resp) => panic!("Unexpected result {:?}", resp),
_ => panic!("Unexpected result"),
}
@ -454,7 +453,7 @@ fn test_batch_execute_error() {
let stmt = conn.prepare("SELECT * FROM foo ORDER BY id");
match stmt {
Err(Error::Db(ref e)) if e.code == UNDEFINED_TABLE => {}
Err(ref e) if e.code() == Some(&UNDEFINED_TABLE) => {}
Err(e) => panic!("unexpected error {:?}", e),
_ => panic!("unexpected success"),
}
@ -519,7 +518,7 @@ FROM (SELECT gs.i
LIMIT 2) ss",
));
match stmt.query(&[]) {
Err(Error::Db(ref e)) if e.code == CARDINALITY_VIOLATION => {}
Err(ref e) if e.code() == Some(&CARDINALITY_VIOLATION) => {}
Err(err) => panic!("Unexpected error {:?}", err),
Ok(_) => panic!("Expected failure"),
};
@ -628,9 +627,10 @@ fn test_wrong_param_type() {
"postgres://postgres@localhost:5433",
TlsMode::None,
));
match conn.execute("SELECT $1::VARCHAR", &[&1i32]) {
Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
res => panic!("unexpected result {:?}", res),
let err = conn.execute("SELECT $1::VARCHAR", &[&1i32]).unwrap_err();
match err.as_conversion() {
Some(e) if e.is::<WrongType>() => {}
_ => panic!("unexpected result {:?}", err),
}
}
@ -710,7 +710,7 @@ fn test_get_was_null() {
let result = or_panic!(stmt.query(&[]));
match result.iter().next().unwrap().get_opt::<_, i32>(0) {
Some(Err(Error::Conversion(..))) => {}
Some(Err(ref e)) if e.as_conversion().is_some() => {}
res => panic!("unexpected result {:?}", res),
};
}
@ -925,7 +925,7 @@ fn test_cancel_query() {
});
match conn.execute("SELECT pg_sleep(10)", &[]) {
Err(Error::Db(ref e)) if e.code == QUERY_CANCELED => {}
Err(ref e) if e.code() == Some(&QUERY_CANCELED) => {}
Err(res) => panic!("Unexpected result {:?}", res),
_ => panic!("Unexpected result"),
}
@ -1018,7 +1018,7 @@ fn test_plaintext_pass_no_pass() {
TlsMode::None,
);
match ret {
Err(ConnectError::ConnectParams(..)) => (),
Err(ref e) if e.as_connection().is_some() => (),
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
}
@ -1031,7 +1031,7 @@ fn test_plaintext_pass_wrong_pass() {
TlsMode::None,
);
match ret {
Err(ConnectError::Db(ref e)) if e.code == INVALID_PASSWORD => {}
Err(ref e) if e.code() == Some(&INVALID_PASSWORD) => {}
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
}
@ -1049,7 +1049,7 @@ fn test_md5_pass() {
fn test_md5_pass_no_pass() {
let ret = Connection::connect("postgres://md5_user@localhost:5433/postgres", TlsMode::None);
match ret {
Err(ConnectError::ConnectParams(..)) => (),
Err(ref e) if e.as_connection().is_some() => (),
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
}
@ -1062,7 +1062,7 @@ fn test_md5_pass_wrong_pass() {
TlsMode::None,
);
match ret {
Err(ConnectError::Db(ref e)) if e.code == INVALID_PASSWORD => {}
Err(ref e) if e.code() == Some(&INVALID_PASSWORD) => {}
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
}
@ -1083,7 +1083,7 @@ fn test_scram_pass_no_pass() {
TlsMode::None,
);
match ret {
Err(ConnectError::ConnectParams(..)) => (),
Err(ref e) if e.as_connection().is_some() => (),
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
}
@ -1096,7 +1096,7 @@ fn test_scram_pass_wrong_pass() {
TlsMode::None,
);
match ret {
Err(ConnectError::Db(ref e)) if e.code == INVALID_PASSWORD => {}
Err(ref e) if e.code() == Some(&INVALID_PASSWORD) => {}
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
}
@ -1110,16 +1110,18 @@ fn test_execute_copy_from_err() {
));
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]));
let stmt = or_panic!(conn.prepare("COPY foo (id) FROM STDIN"));
match stmt.execute(&[]) {
Err(Error::Db(ref err)) if err.message.contains("COPY") => {}
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
let err = stmt.execute(&[]).unwrap_err();
match err.as_db() {
Some(err) if err.message.contains("COPY") => {}
_ => panic!("Unexpected error {:?}", err),
}
let err = stmt.execute(&[]).unwrap_err();
match err.as_db() {
Some(err) if err.message.contains("COPY") => {}
_ => panic!("Unexpected error {:?}", err),
}
match stmt.query(&[]) {
Err(Error::Db(ref err)) if err.message.contains("COPY") => {}
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
};
}
#[test]
@ -1129,10 +1131,10 @@ fn test_batch_execute_copy_from_err() {
TlsMode::None,
));
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]));
match conn.batch_execute("COPY foo (id) FROM STDIN") {
Err(Error::Db(ref err)) if err.message.contains("COPY") => {}
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
let err = conn.batch_execute("COPY foo (id) FROM STDIN").unwrap_err();
match err.as_db() {
Some(err) if err.message.contains("COPY") => {}
_ => panic!("Unexpected error {:?}", err),
}
}
@ -1152,10 +1154,10 @@ fn test_copy_io_error() {
));
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]));
let stmt = or_panic!(conn.prepare("COPY foo (id) FROM STDIN"));
match stmt.copy_in(&[], &mut ErrorReader) {
Err(Error::Io(ref e)) if e.kind() == io::ErrorKind::AddrNotAvailable => {}
Err(err) => panic!("Unexpected error {:?}", err),
_ => panic!("Expected error"),
let err = stmt.copy_in(&[], &mut ErrorReader).unwrap_err();
match err.as_io() {
Some(e) if e.kind() == io::ErrorKind::AddrNotAvailable => {}
_ => panic!("Unexpected error {:?}", err),
}
or_panic!(conn.execute("SELECT 1", &[]));
@ -1194,10 +1196,10 @@ fn test_query_copy_out_err() {
INSERT INTO foo (id) VALUES (0), (1), (2), (3)",
));
let stmt = or_panic!(conn.prepare("COPY foo (id) TO STDOUT"));
match stmt.query(&[]) {
Ok(_) => panic!("unexpected success"),
Err(Error::Io(ref e)) if e.to_string().contains("COPY") => {}
Err(e) => panic!("unexpected error {:?}", e),
let err = stmt.query(&[]).unwrap_err();
match err.as_io() {
Some(e) if e.to_string().contains("COPY") => {}
_ => panic!("unexpected error {:?}", err),
};
}
@ -1237,10 +1239,10 @@ fn test_copy_out_error() {
"COPY (SELECT id FROM foo ORDER BY id) TO STDOUT (OIDS)",
));
let mut buf = vec![];
match stmt.copy_out(&[], &mut buf) {
Ok(_) => panic!("unexpected success"),
Err(Error::Db(..)) => {}
Err(e) => panic!("unexpected error {}", e),
let err = stmt.copy_out(&[], &mut buf).unwrap_err();
match err.as_db() {
Some(_) => {}
_ => panic!("unexpected error {}", err),
}
}
@ -1369,19 +1371,6 @@ fn test_get_bytes() {
);
}
#[test]
fn test_get_opt_wrong_type() {
let conn = Connection::connect("postgres://postgres@localhost:5433", TlsMode::None).unwrap();
let stmt = conn.prepare("SELECT 1::INT").unwrap();
let res = stmt.query(&[]).unwrap();
match res.iter().next().unwrap().get_opt::<_, String>(0) {
Some(Ok(_)) => panic!("unexpected success"),
Some(Err(Error::Conversion(ref e))) if e.is::<WrongType>() => {}
Some(Err(e)) => panic!("unexpected error {}", e),
None => panic!("unexpected None"),
}
}
#[test]
fn url_unencoded_password() {
assert!(

View File

@ -357,10 +357,10 @@ fn test_slice_wrong_type() {
let stmt = conn.prepare("SELECT * FROM foo WHERE id = ANY($1)")
.unwrap();
match stmt.query(&[&&["hi"][..]]) {
Ok(_) => panic!("Unexpected success"),
Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
Err(e) => panic!("Unexpected error {:?}", e),
let err = stmt.query(&[&&["hi"][..]]).unwrap_err();
match err.as_conversion() {
Some(e) if e.is::<WrongType>() => {}
_ => panic!("Unexpected error {:?}", err),
};
}
@ -369,10 +369,10 @@ fn test_slice_range() {
let conn = Connection::connect("postgres://postgres@localhost:5433", TlsMode::None).unwrap();
let stmt = conn.prepare("SELECT $1::INT8RANGE").unwrap();
match stmt.query(&[&&[1i64][..]]) {
Ok(_) => panic!("Unexpected success"),
Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
Err(e) => panic!("Unexpected error {:?}", e),
let err = stmt.query(&[&&[1i64][..]]).unwrap_err();
match err.as_conversion() {
Some(e) if e.is::<WrongType>() => {}
_ => panic!("Unexpected error {:?}", err),
};
}