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