1use std::borrow::Cow;
2use std::io;
3use std::result;
4use std::str::Utf8Error;
5use std::string::FromUtf8Error;
6
7use thiserror::Error;
8#[cfg(feature = "tokio_io")]
9use tokio::time::error::Elapsed;
10use url::ParseError;
11
12pub type Result<T> = result::Result<T, Error>;
14
15#[derive(Debug, Error)]
17pub enum Error {
18 #[error("Driver error: `{}`", _0)]
19 Driver(#[source] DriverError),
20
21 #[error("Input/output error: `{}`", _0)]
22 IO(#[source] io::Error),
23
24 #[error("Connections error: `{}`", _0)]
25 Connection(#[source] ConnectionError),
26
27 #[error("Other error: `{}`", _0)]
28 Other(Cow<'static, str>),
29
30 #[error("Server error: `{}`", _0)]
31 Server(#[source] ServerError),
32
33 #[error("URL error: `{}`", _0)]
34 Url(#[source] UrlError),
35
36 #[error("From SQL error: `{}`", _0)]
37 FromSql(#[source] FromSqlError)
38}
39
40#[derive(Debug, Error, Clone)]
42#[error("ERROR {} ({:?}): {}", name, code, message)]
43pub struct ServerError {
44 pub code: u32,
45 pub name: String,
46 pub message: String,
47 pub stack_trace: String
48}
49
50#[derive(Debug, Error)]
52pub enum ConnectionError {
53 #[error("TLS connection requires hostname to be provided")]
54 TlsHostNotProvided,
55
56 #[error("Input/output error: `{}`", _0)]
57 IOError(#[source] io::Error),
58
59 #[cfg(feature = "tls")]
60 #[error("TLS connection error: `{}`", _0)]
61 TlsError(#[source] native_tls::Error)
62}
63
64#[derive(Debug, Error, Clone)]
66pub enum UrlError {
67 #[error("Invalid or incomplete connection URL")]
68 Invalid,
69
70 #[error("Invalid value `{}' for connection URL parameter `{}'", value, param)]
71 InvalidParamValue { param: String, value: String },
72
73 #[error("URL parse error: {}", _0)]
74 Parse(#[source] ParseError),
75
76 #[error("Unknown connection URL parameter `{}'", param)]
77 UnknownParameter { param: String },
78
79 #[error("Unsupported connection URL scheme `{}'", scheme)]
80 UnsupportedScheme { scheme: String }
81}
82
83#[derive(Debug, Error, Clone)]
85pub enum DriverError {
86 #[error("Varint overflows a 64-bit integer.")]
87 Overflow,
88
89 #[error("Unknown packet 0x{:x}.", packet)]
90 UnknownPacket { packet: u64 },
91
92 #[error("Unexpected packet.")]
93 UnexpectedPacket,
94
95 #[error("Timeout error.")]
96 Timeout,
97
98 #[error("Invalid utf-8 sequence.")]
99 Utf8Error(Utf8Error),
100
101 #[error("UnknownSetting name {}", name)]
102 UnknownSetting { name: String }
103}
104
105#[derive(Debug, Error, Clone)]
107pub enum FromSqlError {
108 #[error("SqlType::{} cannot be cast to {}.", src, dst)]
109 InvalidType {
110 src: Cow<'static, str>,
111 dst: Cow<'static, str>
112 },
113
114 #[error("Out of range.")]
115 OutOfRange,
116
117 #[error("Unsupported operation.")]
118 UnsupportedOperation
119}
120
121impl Error {
122 pub(crate) fn is_would_block(&self) -> bool {
123 if let Error::IO(ref e) = self {
124 if e.kind() == io::ErrorKind::WouldBlock {
125 return true;
126 }
127 }
128 false
129 }
130}
131
132impl From<ConnectionError> for Error {
133 fn from(error: ConnectionError) -> Self {
134 Error::Connection(error)
135 }
136}
137
138#[cfg(feature = "tls")]
139impl From<native_tls::Error> for ConnectionError {
140 fn from(error: native_tls::Error) -> Self {
141 ConnectionError::TlsError(error)
142 }
143}
144
145impl From<DriverError> for Error {
146 fn from(err: DriverError) -> Self {
147 Error::Driver(err)
148 }
149}
150
151impl From<io::Error> for Error {
152 fn from(err: io::Error) -> Self {
153 Error::IO(err)
154 }
155}
156
157impl From<Error> for io::Error {
158 fn from(err: Error) -> Self {
159 match err {
160 Error::IO(error) => error,
161 e => io::Error::new(io::ErrorKind::Other, e.to_string())
162 }
163 }
164}
165
166impl From<ServerError> for Error {
167 fn from(err: ServerError) -> Self {
168 Error::Server(err)
169 }
170}
171
172impl From<UrlError> for Error {
173 fn from(err: UrlError) -> Self {
174 Error::Url(err)
175 }
176}
177
178impl From<String> for Error {
179 fn from(err: String) -> Self {
180 Error::Other(Cow::from(err))
181 }
182}
183
184impl From<&str> for Error {
185 fn from(err: &str) -> Self {
186 Error::Other(err.to_string().into())
187 }
188}
189
190impl From<FromUtf8Error> for Error {
191 fn from(err: FromUtf8Error) -> Self {
192 Error::Other(err.to_string().into())
193 }
194}
195
196#[cfg(feature = "tokio_io")]
197impl From<Elapsed> for Error {
198 fn from(_err: Elapsed) -> Self {
199 Error::Driver(DriverError::Timeout)
200 }
201}
202
203impl From<ParseError> for Error {
204 fn from(err: ParseError) -> Self {
205 Error::Url(UrlError::Parse(err))
206 }
207}
208
209impl From<Utf8Error> for Error {
210 fn from(err: Utf8Error) -> Self {
211 Error::Driver(DriverError::Utf8Error(err))
212 }
213}
214
215impl Error {
216 pub fn exception_name(&self) -> &str {
217 match self {
218 Error::Driver(_) => "DriverException",
219 Error::IO(_) => "IOException",
220 Error::Connection(_) => "ConnectionException",
221 Error::Other(_) => "OtherException",
222 Error::Server(e) => e.name.as_str(),
223 Error::Url(_) => "URLException",
224 Error::FromSql(_) => "SQLException",
225 }
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 #[test]
232 fn to_std_error_without_recursion() {
233 let src_err: super::Error = From::from("Somth went wrong.");
234 let dst_err: Box<dyn std::error::Error> = src_err.into();
235 assert_eq!(dst_err.to_string(), "Other error: `Somth went wrong.`");
236 }
237
238 #[test]
239 fn to_io_error_without_recursion() {
240 let src_err: super::Error = From::from("Somth went wrong.");
241 let dst_err: std::io::Error = src_err.into();
242 assert_eq!(dst_err.to_string(), "Other error: `Somth went wrong.`");
243 }
244}