opensrv_clickhouse/
errors.rs

1// Copyright 2021 Datafuse Labs.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::borrow::Cow;
16use std::io;
17use std::result;
18use std::str::Utf8Error;
19use std::string::FromUtf8Error;
20
21use thiserror::Error;
22use tokio::time::error::Elapsed;
23use url::ParseError;
24
25/// Result type alias for this library.
26pub type Result<T> = result::Result<T, Error>;
27
28/// This type enumerates library errors.
29#[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] io::Error),
36
37    #[error("Connections error: `{}`", _0)]
38    Connection(#[source] ConnectionError),
39
40    #[error("Other error: `{}`", _0)]
41    Other(Cow<'static, str>),
42
43    #[error("Server error: `{}`", _0)]
44    Server(#[source] ServerError),
45
46    #[error("URL error: `{}`", _0)]
47    Url(#[source] UrlError),
48
49    #[error("From SQL error: `{}`", _0)]
50    FromSql(#[source] FromSqlError),
51}
52
53/// This type represents Clickhouse server error.
54#[derive(Debug, Error, Clone)]
55#[error("ERROR {} ({:?}): {}", name, code, message)]
56pub struct ServerError {
57    pub code: u32,
58    pub name: String,
59    pub message: String,
60    pub stack_trace: String,
61}
62
63/// This type enumerates connection errors.
64#[derive(Debug, Error)]
65pub enum ConnectionError {
66    #[error("TLS connection requires hostname to be provided")]
67    TlsHostNotProvided,
68
69    #[error("Input/output error: `{}`", _0)]
70    IOError(#[source] io::Error),
71
72    #[cfg(feature = "tls")]
73    #[error("TLS connection error: `{}`", _0)]
74    TlsError(#[source] tokio_native_tls::native_tls::Error),
75}
76
77/// This type enumerates connection URL errors.
78#[derive(Debug, Error, Clone)]
79pub enum UrlError {
80    #[error("Invalid or incomplete connection URL")]
81    Invalid,
82
83    #[error("Invalid value `{}' for connection URL parameter `{}'", value, param)]
84    InvalidParamValue { param: String, value: String },
85
86    #[error("URL parse error: {}", _0)]
87    Parse(#[source] ParseError),
88
89    #[error("Unknown connection URL parameter `{}'", param)]
90    UnknownParameter { param: String },
91
92    #[error("Unsupported connection URL scheme `{}'", scheme)]
93    UnsupportedScheme { scheme: String },
94}
95
96/// This type enumerates driver errors.
97#[derive(Debug, Error, Clone)]
98pub enum DriverError {
99    #[error("Varint overflows a 64-bit integer.")]
100    Overflow,
101
102    #[error("Unknown packet 0x{:x}.", packet)]
103    UnknownPacket { packet: u64 },
104
105    #[error("Unexpected packet.")]
106    UnexpectedPacket,
107
108    #[error("Timeout error.")]
109    Timeout,
110
111    #[error("Invalid utf-8 sequence.")]
112    Utf8Error(Utf8Error),
113
114    #[error("UnknownSetting name {}", name)]
115    UnknownSetting { name: String },
116}
117
118/// This type enumerates cast from sql type errors.
119#[derive(Debug, Error, Clone)]
120pub enum FromSqlError {
121    #[error("SqlType::{} cannot be cast to {}.", src, dst)]
122    InvalidType {
123        src: Cow<'static, str>,
124        dst: Cow<'static, str>,
125    },
126
127    #[error("Out of range.")]
128    OutOfRange,
129
130    #[error("Unsupported operation.")]
131    UnsupportedOperation,
132}
133
134impl Error {
135    pub(crate) fn is_would_block(&self) -> bool {
136        if let Error::IO(ref e) = self {
137            if e.kind() == io::ErrorKind::WouldBlock {
138                return true;
139            }
140        }
141        false
142    }
143}
144
145impl From<ConnectionError> for Error {
146    fn from(error: ConnectionError) -> Self {
147        Error::Connection(error)
148    }
149}
150
151#[cfg(feature = "tls")]
152impl From<tokio_native_tls::native_tls::Error> for ConnectionError {
153    fn from(error: tokio_native_tls::native_tls::Error) -> Self {
154        ConnectionError::TlsError(error)
155    }
156}
157
158impl From<DriverError> for Error {
159    fn from(err: DriverError) -> Self {
160        Error::Driver(err)
161    }
162}
163
164impl From<io::Error> for Error {
165    fn from(err: io::Error) -> Self {
166        Error::IO(err)
167    }
168}
169
170impl From<Error> for io::Error {
171    fn from(err: Error) -> Self {
172        match err {
173            Error::IO(error) => error,
174            e => io::Error::new(io::ErrorKind::Other, e.to_string()),
175        }
176    }
177}
178
179impl From<ServerError> for Error {
180    fn from(err: ServerError) -> Self {
181        Error::Server(err)
182    }
183}
184
185impl From<UrlError> for Error {
186    fn from(err: UrlError) -> Self {
187        Error::Url(err)
188    }
189}
190
191impl From<String> for Error {
192    fn from(err: String) -> Self {
193        Error::Other(Cow::from(err))
194    }
195}
196
197impl From<&str> for Error {
198    fn from(err: &str) -> Self {
199        Error::Other(err.to_string().into())
200    }
201}
202
203impl From<FromUtf8Error> for Error {
204    fn from(err: FromUtf8Error) -> Self {
205        Error::Other(err.to_string().into())
206    }
207}
208
209impl From<Elapsed> for Error {
210    fn from(_err: Elapsed) -> Self {
211        Error::Driver(DriverError::Timeout)
212    }
213}
214
215impl From<ParseError> for Error {
216    fn from(err: ParseError) -> Self {
217        Error::Url(UrlError::Parse(err))
218    }
219}
220
221impl From<Utf8Error> for Error {
222    fn from(err: Utf8Error) -> Self {
223        Error::Driver(DriverError::Utf8Error(err))
224    }
225}
226
227impl Error {
228    pub fn exception_name(&self) -> &str {
229        match self {
230            Error::Driver(_) => "DriverException",
231            Error::IO(_) => "IOException",
232            Error::Connection(_) => "ConnectionException",
233            Error::Other(_) => "OtherException",
234            Error::Server(e) => e.name.as_str(),
235            Error::Url(_) => "URLException",
236            Error::FromSql(_) => "SQLException",
237        }
238    }
239}