1pub 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
25pub type Result<T> = result::Result<T, Error>;
27
28pub(crate) const MAX_STATEMENT_PARAMS: usize = u16::MAX as usize;
31
32#[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 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#[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#[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#[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#[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
292impl 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}