mysql_async/error/
mod.rs

1// Copyright (c) 2016 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9pub use url::ParseError;
10
11pub mod tls;
12
13use mysql_common::{
14    named_params::MixedParamsError, params::MissingNamedParameterError,
15    proto::codec::error::PacketCodecError, row::Row, value::Value,
16};
17use thiserror::Error;
18
19use std::{io, result};
20
21/// Result type alias for this library.
22pub type Result<T> = result::Result<T, Error>;
23
24/// This type enumerates library errors.
25#[derive(Debug, Error)]
26pub enum Error {
27    #[error("Driver error: `{}'", _0)]
28    Driver(#[source] DriverError),
29
30    #[error("Input/output error: {}", _0)]
31    Io(#[source] IoError),
32
33    #[error("Other error: {}", _0)]
34    Other(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
35
36    #[error("Server error: `{}'", _0)]
37    Server(#[source] ServerError),
38
39    #[error("URL error: `{}'", _0)]
40    Url(#[source] UrlError),
41}
42
43impl Error {
44    /// Returns true if the error means that connection is broken.
45    pub fn is_fatal(&self) -> bool {
46        match self {
47            Error::Driver(_) | Error::Io(_) | Error::Other(_) | Error::Url(_) => true,
48            Error::Server(_) => false,
49        }
50    }
51}
52
53/// This type enumerates IO errors.
54#[derive(Debug, Error)]
55pub enum IoError {
56    #[error("Input/output error: {}", _0)]
57    Io(#[source] io::Error),
58    #[cfg(any(feature = "native-tls-tls", feature = "rustls-tls"))]
59    #[error("TLS error: `{}'", _0)]
60    Tls(#[source] tls::TlsError),
61}
62
63/// This type represents MySql server error.
64#[derive(Debug, Error, Clone, Eq, PartialEq)]
65#[error("ERROR {} ({}): {}", state, code, message)]
66pub struct ServerError {
67    pub code: u16,
68    pub message: String,
69    pub state: String,
70}
71
72/// This type enumerates connection URL errors.
73#[derive(Debug, Error, Clone, Eq, PartialEq)]
74pub enum UrlError {
75    #[error("Connection URL parameter `{}' requires feature `{}'", param, feature)]
76    FeatureRequired { feature: String, param: String },
77
78    #[error("Invalid or incomplete connection URL")]
79    Invalid,
80
81    #[error("Invalid value `{}' for connection URL parameter `{}'", value, param)]
82    InvalidParamValue { param: String, value: String },
83
84    #[error("Invalid pool constraints: pool_min ({}) > pool_max ({}).", min, max)]
85    InvalidPoolConstraints { min: usize, max: usize },
86
87    #[error("URL parse error: {}", _0)]
88    Parse(#[source] ParseError),
89
90    #[error("Unknown connection URL parameter `{}'", param)]
91    UnknownParameter { param: String },
92
93    #[error("Unsupported connection URL scheme `{}'", scheme)]
94    UnsupportedScheme { scheme: String },
95}
96
97/// This type enumerates driver errors.
98#[derive(Debug, Error)]
99pub enum DriverError {
100    #[error("Can't parse server version from string `{}'.", version_string)]
101    CantParseServerVersion { version_string: String },
102
103    #[error("Connection to the server is closed.")]
104    ConnectionClosed,
105
106    #[error("Error converting from mysql value.")]
107    FromValue { value: Value },
108
109    #[error("Error converting from mysql row.")]
110    FromRow { row: Row },
111
112    #[error("Missing named parameter `{}'.", String::from_utf8_lossy(name))]
113    MissingNamedParam { name: Vec<u8> },
114
115    #[error("Named and positional parameters mixed in one statement.")]
116    MixedParams,
117
118    #[error("Named parameters supplied for positional query.")]
119    NamedParamsForPositionalQuery,
120
121    #[error("Transactions couldn't be nested.")]
122    NestedTransaction,
123
124    #[error("Packet out of order.")]
125    PacketOutOfOrder,
126
127    #[error("Pool was disconnected.")]
128    PoolDisconnected,
129
130    #[error("`SET TRANSACTION READ (ONLY|WRITE)' is not supported in your MySQL version.")]
131    ReadOnlyTransNotSupported,
132
133    #[error(
134        "Statement takes {} parameters but {} was supplied.",
135        required,
136        supplied
137    )]
138    StmtParamsMismatch { required: u16, supplied: u16 },
139
140    #[error("Unexpected packet.")]
141    UnexpectedPacket { payload: Vec<u8> },
142
143    #[error("Unknown authentication plugin `{}'.", name)]
144    UnknownAuthPlugin { name: String },
145
146    #[error("Packet too large.")]
147    PacketTooLarge,
148
149    #[error("Bad compressed packet header.")]
150    BadCompressedPacketHeader,
151
152    #[error("Named pipe connections temporary disabled (see tokio-rs/tokio#3118)")]
153    NamedPipesDisabled,
154
155    #[error("`mysql_old_password` plugin is insecure and disabled by default")]
156    MysqlOldPasswordDisabled,
157
158    #[error("LOCAL INFILE error: {}", _0)]
159    LocalInfile(#[from] LocalInfileError),
160
161    #[error("No private key found in the file specified")]
162    NoKeyFound,
163
164    #[error("Client asked for SSL but server does not have this capability")]
165    NoClientSslFlagFromServer,
166
167    #[error("mysql_clear_password must be enabled on the client side")]
168    CleartextPluginDisabled,
169}
170
171#[derive(Debug, Error)]
172pub enum LocalInfileError {
173    #[error("The given path is not in the while list: {}", _0)]
174    PathIsNotInTheWhiteList(String),
175    #[error("Error reading `INFILE` data: {}", _0)]
176    ReadError(#[from] io::Error),
177    #[error("Can't handle local infile request. Handler is not specified.")]
178    NoHandler,
179    #[error(transparent)]
180    OtherError(Box<dyn std::error::Error + Send + Sync + 'static>),
181}
182
183impl LocalInfileError {
184    pub fn other<T>(err: T) -> Self
185    where
186        T: std::error::Error + Send + Sync + 'static,
187    {
188        Self::OtherError(Box::new(err))
189    }
190}
191
192impl From<LocalInfileError> for Error {
193    fn from(err: LocalInfileError) -> Self {
194        Self::Driver(err.into())
195    }
196}
197
198impl From<DriverError> for Error {
199    fn from(err: DriverError) -> Self {
200        Error::Driver(err)
201    }
202}
203
204impl From<IoError> for Error {
205    fn from(io: IoError) -> Self {
206        Error::Io(io)
207    }
208}
209
210impl From<io::Error> for IoError {
211    fn from(err: io::Error) -> Self {
212        IoError::Io(err)
213    }
214}
215
216impl From<io::Error> for Error {
217    fn from(err: io::Error) -> Self {
218        Error::Io(err.into())
219    }
220}
221
222impl From<ServerError> for Error {
223    fn from(err: ServerError) -> Self {
224        Error::Server(err)
225    }
226}
227
228impl From<UrlError> for Error {
229    fn from(err: UrlError) -> Self {
230        Error::Url(err)
231    }
232}
233
234#[cfg(feature = "native-tls-tls")]
235impl From<native_tls::Error> for IoError {
236    fn from(err: native_tls::Error) -> Self {
237        IoError::Tls(tls::TlsError::TlsError(err))
238    }
239}
240
241impl From<mysql_common::packets::ServerError<'_>> for ServerError {
242    fn from(packet: mysql_common::packets::ServerError<'_>) -> Self {
243        ServerError {
244            code: packet.error_code(),
245            message: packet.message_str().into(),
246            state: packet
247                .sql_state_ref()
248                .map(|s| s.as_str().into_owned())
249                .unwrap_or_else(|| "HY000".to_owned()),
250        }
251    }
252}
253
254impl From<mysql_common::packets::ServerError<'_>> for Error {
255    fn from(packet: mysql_common::packets::ServerError<'_>) -> Self {
256        Error::Server(packet.into())
257    }
258}
259
260// For convenience
261impl From<(Error, crate::io::Stream)> for Error {
262    fn from((err, _): (Error, crate::io::Stream)) -> Self {
263        err
264    }
265}
266
267impl From<MissingNamedParameterError> for DriverError {
268    fn from(err: MissingNamedParameterError) -> Self {
269        DriverError::MissingNamedParam { name: err.0 }
270    }
271}
272
273impl From<MissingNamedParameterError> for Error {
274    fn from(err: MissingNamedParameterError) -> Self {
275        Error::Driver(err.into())
276    }
277}
278
279impl From<MixedParamsError> for DriverError {
280    fn from(_err: MixedParamsError) -> Self {
281        DriverError::MixedParams
282    }
283}
284
285impl From<MixedParamsError> for Error {
286    fn from(err: MixedParamsError) -> Self {
287        Error::Driver(err.into())
288    }
289}
290
291impl From<ParseError> for UrlError {
292    fn from(err: ParseError) -> Self {
293        UrlError::Parse(err)
294    }
295}
296
297impl From<ParseError> for Error {
298    fn from(err: ParseError) -> Self {
299        Error::Url(err.into())
300    }
301}
302
303impl From<PacketCodecError> for IoError {
304    fn from(err: PacketCodecError) -> Self {
305        match err {
306            PacketCodecError::Io(err) => err.into(),
307            PacketCodecError::PacketTooLarge => {
308                io::Error::new(io::ErrorKind::Other, "packet too large").into()
309            }
310            PacketCodecError::PacketsOutOfSync => {
311                io::Error::new(io::ErrorKind::Other, "packet out of order").into()
312            }
313            PacketCodecError::BadCompressedPacketHeader => {
314                io::Error::new(io::ErrorKind::Other, "bad compressed packet header").into()
315            }
316        }
317    }
318}
319
320impl From<PacketCodecError> for Error {
321    fn from(err: PacketCodecError) -> Self {
322        Error::Io(err.into())
323    }
324}