Skip to main content

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