pub use url::ParseError;
pub mod tls;
use mysql_common::{
named_params::MixedParamsError, params::MissingNamedParameterError,
proto::codec::error::PacketCodecError, row::Row, value::Value,
};
use thiserror::Error;
use std::{io, result};
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Error)]
pub enum Error {
#[error("Driver error: `{}'", _0)]
Driver(#[source] DriverError),
#[error("Input/output error: {}", _0)]
Io(#[source] IoError),
#[error("Other error: {}", _0)]
Other(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
#[error("Server error: `{}'", _0)]
Server(#[source] ServerError),
#[error("URL error: `{}'", _0)]
Url(#[source] UrlError),
}
impl Error {
pub fn is_fatal(&self) -> bool {
match self {
Error::Driver(_) | Error::Io(_) | Error::Other(_) | Error::Url(_) => true,
Error::Server(_) => false,
}
}
}
#[derive(Debug, Error)]
pub enum IoError {
#[error("Input/output error: {}", _0)]
Io(#[source] io::Error),
#[cfg(any(feature = "native-tls-tls", feature = "rustls-tls"))]
#[error("TLS error: `{}'", _0)]
Tls(#[source] tls::TlsError),
}
#[derive(Debug, Error, Clone, Eq, PartialEq)]
#[error("ERROR {} ({}): {}", state, code, message)]
pub struct ServerError {
pub code: u16,
pub message: String,
pub state: String,
}
#[derive(Debug, Error, Clone, Eq, PartialEq)]
pub enum UrlError {
#[error("Connection URL parameter `{}' requires feature `{}'", param, feature)]
FeatureRequired { feature: String, param: String },
#[error("Invalid or incomplete connection URL")]
Invalid,
#[error("Invalid value `{}' for connection URL parameter `{}'", value, param)]
InvalidParamValue { param: String, value: String },
#[error("Invalid pool constraints: pool_min ({}) > pool_max ({}).", min, max)]
InvalidPoolConstraints { min: usize, max: usize },
#[error("URL parse error: {}", _0)]
Parse(#[source] ParseError),
#[error("Unknown connection URL parameter `{}'", param)]
UnknownParameter { param: String },
#[error("Unsupported connection URL scheme `{}'", scheme)]
UnsupportedScheme { scheme: String },
}
#[derive(Debug, Error)]
pub enum DriverError {
#[error("Can't parse server version from string `{}'.", version_string)]
CantParseServerVersion { version_string: String },
#[error("Connection to the server is closed.")]
ConnectionClosed,
#[error("Error converting from mysql value.")]
FromValue { value: Value },
#[error("Error converting from mysql row.")]
FromRow { row: Row },
#[error("Missing named parameter `{}'.", String::from_utf8_lossy(name))]
MissingNamedParam { name: Vec<u8> },
#[error("Named and positional parameters mixed in one statement.")]
MixedParams,
#[error("Named parameters supplied for positional query.")]
NamedParamsForPositionalQuery,
#[error("Transactions couldn't be nested.")]
NestedTransaction,
#[error("Packet out of order.")]
PacketOutOfOrder,
#[error("Pool was disconnected.")]
PoolDisconnected,
#[error("`SET TRANSACTION READ (ONLY|WRITE)' is not supported in your MySQL version.")]
ReadOnlyTransNotSupported,
#[error(
"Statement takes {} parameters but {} was supplied.",
required,
supplied
)]
StmtParamsMismatch { required: u16, supplied: u16 },
#[error("Unexpected packet.")]
UnexpectedPacket { payload: Vec<u8> },
#[error("Unknown authentication plugin `{}'.", name)]
UnknownAuthPlugin { name: String },
#[error("Packet too large.")]
PacketTooLarge,
#[error("Bad compressed packet header.")]
BadCompressedPacketHeader,
#[error("Named pipe connections temporary disabled (see tokio-rs/tokio#3118)")]
NamedPipesDisabled,
#[error("`mysql_old_password` plugin is insecure and disabled by default")]
MysqlOldPasswordDisabled,
#[error("LOCAL INFILE error: {}", _0)]
LocalInfile(#[from] LocalInfileError),
#[error("No private key found in the file specified")]
NoKeyFound,
#[error("Client asked for SSL but server does not have this capability")]
NoClientSslFlagFromServer,
#[error("mysql_clear_password must be enabled on the client side")]
CleartextPluginDisabled,
}
#[derive(Debug, Error)]
pub enum LocalInfileError {
#[error("The given path is not in the while list: {}", _0)]
PathIsNotInTheWhiteList(String),
#[error("Error reading `INFILE` data: {}", _0)]
ReadError(#[from] io::Error),
#[error("Can't handle local infile request. Handler is not specified.")]
NoHandler,
#[error(transparent)]
OtherError(Box<dyn std::error::Error + Send + Sync + 'static>),
}
impl LocalInfileError {
pub fn other<T>(err: T) -> Self
where
T: std::error::Error + Send + Sync + 'static,
{
Self::OtherError(Box::new(err))
}
}
impl From<LocalInfileError> for Error {
fn from(err: LocalInfileError) -> Self {
Self::Driver(err.into())
}
}
impl From<DriverError> for Error {
fn from(err: DriverError) -> Self {
Error::Driver(err)
}
}
impl From<IoError> for Error {
fn from(io: IoError) -> Self {
Error::Io(io)
}
}
impl From<io::Error> for IoError {
fn from(err: io::Error) -> Self {
IoError::Io(err)
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::Io(err.into())
}
}
impl From<ServerError> for Error {
fn from(err: ServerError) -> Self {
Error::Server(err)
}
}
impl From<UrlError> for Error {
fn from(err: UrlError) -> Self {
Error::Url(err)
}
}
#[cfg(feature = "native-tls-tls")]
impl From<native_tls::Error> for IoError {
fn from(err: native_tls::Error) -> Self {
IoError::Tls(tls::TlsError::TlsError(err))
}
}
impl From<mysql_common::packets::ServerError<'_>> for ServerError {
fn from(packet: mysql_common::packets::ServerError<'_>) -> Self {
ServerError {
code: packet.error_code(),
message: packet.message_str().into(),
state: packet
.sql_state_ref()
.map(|s| s.as_str().into_owned())
.unwrap_or_else(|| "HY000".to_owned()),
}
}
}
impl From<mysql_common::packets::ServerError<'_>> for Error {
fn from(packet: mysql_common::packets::ServerError<'_>) -> Self {
Error::Server(packet.into())
}
}
impl From<(Error, crate::io::Stream)> for Error {
fn from((err, _): (Error, crate::io::Stream)) -> Self {
err
}
}
impl From<MissingNamedParameterError> for DriverError {
fn from(err: MissingNamedParameterError) -> Self {
DriverError::MissingNamedParam { name: err.0 }
}
}
impl From<MissingNamedParameterError> for Error {
fn from(err: MissingNamedParameterError) -> Self {
Error::Driver(err.into())
}
}
impl From<MixedParamsError> for DriverError {
fn from(_err: MixedParamsError) -> Self {
DriverError::MixedParams
}
}
impl From<MixedParamsError> for Error {
fn from(err: MixedParamsError) -> Self {
Error::Driver(err.into())
}
}
impl From<ParseError> for UrlError {
fn from(err: ParseError) -> Self {
UrlError::Parse(err)
}
}
impl From<ParseError> for Error {
fn from(err: ParseError) -> Self {
Error::Url(err.into())
}
}
impl From<PacketCodecError> for IoError {
fn from(err: PacketCodecError) -> Self {
match err {
PacketCodecError::Io(err) => err.into(),
PacketCodecError::PacketTooLarge => {
io::Error::new(io::ErrorKind::Other, "packet too large").into()
}
PacketCodecError::PacketsOutOfSync => {
io::Error::new(io::ErrorKind::Other, "packet out of order").into()
}
PacketCodecError::BadCompressedPacketHeader => {
io::Error::new(io::ErrorKind::Other, "bad compressed packet header").into()
}
}
}
}
impl From<PacketCodecError> for Error {
fn from(err: PacketCodecError) -> Self {
Error::Io(err.into())
}
}