clickhouse_rs_async/errors/
mod.rs

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