1use std::any::type_name;
4use std::borrow::Cow;
5use std::error::Error as StdError;
6use std::fmt::Display;
7use std::io;
8
9use crate::database::Database;
10
11use crate::type_info::TypeInfo;
12use crate::types::Type;
13
14pub type Result<T, E = Error> = ::std::result::Result<T, E>;
16
17pub type BoxDynError = Box<dyn StdError + 'static + Send + Sync>;
20
21#[derive(thiserror::Error, Debug)]
26#[error("unexpected null; try decoding as an `Option`")]
27pub struct UnexpectedNullError;
28
29#[derive(Debug, thiserror::Error)]
31#[non_exhaustive]
32pub enum Error {
33 #[error("error with configuration: {0}")]
35 Configuration(#[source] BoxDynError),
36
37 #[error("error returned from database: {0}")]
39 Database(#[source] Box<dyn DatabaseError>),
40
41 #[error("error communicating with database: {0}")]
43 Io(#[from] io::Error),
44
45 #[error("error occurred while attempting to establish a TLS connection: {0}")]
47 Tls(#[source] BoxDynError),
48
49 #[error("encountered unexpected or invalid data: {0}")]
54 Protocol(String),
55
56 #[error("no rows returned by a query that expected to return at least one row")]
58 RowNotFound,
59
60 #[error("type named {type_name} not found")]
62 TypeNotFound { type_name: String },
63
64 #[error("column index out of bounds: the len is {len}, but the index is {index}")]
66 ColumnIndexOutOfBounds { index: usize, len: usize },
67
68 #[error("no column found for name: {0}")]
70 ColumnNotFound(String),
71
72 #[error("error occurred while decoding column {index}: {source}")]
74 ColumnDecode {
75 index: String,
76
77 #[source]
78 source: BoxDynError,
79 },
80
81 #[error("error occured while encoding a value: {0}")]
83 Encode(#[source] BoxDynError),
84
85 #[error("error occurred while decoding: {0}")]
87 Decode(#[source] BoxDynError),
88
89 #[error("error in Any driver mapping: {0}")]
91 AnyDriverError(#[source] BoxDynError),
92
93 #[error("pool timed out while waiting for an open connection")]
98 PoolTimedOut,
99
100 #[error("attempted to acquire a connection on a closed pool")]
105 PoolClosed,
106
107 #[error("attempted to communicate with a crashed background worker")]
109 WorkerCrashed,
110
111 #[cfg(feature = "migrate")]
112 #[error("{0}")]
113 Migrate(#[source] Box<crate::migrate::MigrateError>),
114}
115
116impl StdError for Box<dyn DatabaseError> {}
117
118impl Error {
119 pub fn into_database_error(self) -> Option<Box<dyn DatabaseError + 'static>> {
120 match self {
121 Error::Database(err) => Some(err),
122 _ => None,
123 }
124 }
125
126 pub fn as_database_error(&self) -> Option<&(dyn DatabaseError + 'static)> {
127 match self {
128 Error::Database(err) => Some(&**err),
129 _ => None,
130 }
131 }
132
133 #[doc(hidden)]
134 #[inline]
135 pub fn protocol(err: impl Display) -> Self {
136 Error::Protocol(err.to_string())
137 }
138
139 #[doc(hidden)]
140 #[inline]
141 pub fn config(err: impl StdError + Send + Sync + 'static) -> Self {
142 Error::Configuration(err.into())
143 }
144
145 pub(crate) fn tls(err: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {
146 Error::Tls(err.into())
147 }
148
149 #[doc(hidden)]
150 #[inline]
151 pub fn decode(err: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {
152 Error::Decode(err.into())
153 }
154}
155
156pub fn mismatched_types<DB: Database, T: Type<DB>>(ty: &DB::TypeInfo) -> BoxDynError {
157 format!(
159 "mismatched types; Rust type `{}` (as SQL type `{}`) is not compatible with SQL type `{}`",
160 type_name::<T>(),
161 T::type_info().name(),
162 ty.name()
163 )
164 .into()
165}
166
167#[derive(Debug, PartialEq, Eq)]
172#[non_exhaustive]
173pub enum ErrorKind {
174 UniqueViolation,
176 ForeignKeyViolation,
178 NotNullViolation,
180 CheckViolation,
182 Other,
184}
185
186pub trait DatabaseError: 'static + Send + Sync + StdError {
188 fn message(&self) -> &str;
190
191 fn code(&self) -> Option<Cow<'_, str>> {
193 None
194 }
195
196 #[doc(hidden)]
197 fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static);
198
199 #[doc(hidden)]
200 fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static);
201
202 #[doc(hidden)]
203 fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static>;
204
205 #[doc(hidden)]
206 fn is_transient_in_connect_phase(&self) -> bool {
207 false
208 }
209
210 fn constraint(&self) -> Option<&str> {
216 None
217 }
218
219 fn table(&self) -> Option<&str> {
224 None
225 }
226
227 fn kind(&self) -> ErrorKind;
232
233 fn is_unique_violation(&self) -> bool {
235 matches!(self.kind(), ErrorKind::UniqueViolation)
236 }
237
238 fn is_foreign_key_violation(&self) -> bool {
240 matches!(self.kind(), ErrorKind::ForeignKeyViolation)
241 }
242
243 fn is_check_violation(&self) -> bool {
245 matches!(self.kind(), ErrorKind::CheckViolation)
246 }
247}
248
249impl dyn DatabaseError {
250 pub fn downcast_ref<E: DatabaseError>(&self) -> &E {
259 self.try_downcast_ref().unwrap_or_else(|| {
260 panic!("downcast to wrong DatabaseError type; original error: {self}")
261 })
262 }
263
264 pub fn downcast<E: DatabaseError>(self: Box<Self>) -> Box<E> {
272 self.try_downcast()
273 .unwrap_or_else(|e| panic!("downcast to wrong DatabaseError type; original error: {e}"))
274 }
275
276 #[inline]
279 pub fn try_downcast_ref<E: DatabaseError>(&self) -> Option<&E> {
280 self.as_error().downcast_ref()
281 }
282
283 #[inline]
285 pub fn try_downcast<E: DatabaseError>(self: Box<Self>) -> Result<Box<E>, Box<Self>> {
286 if self.as_error().is::<E>() {
287 Ok(self.into_error().downcast().unwrap())
288 } else {
289 Err(self)
290 }
291 }
292}
293
294impl<E> From<E> for Error
295where
296 E: DatabaseError,
297{
298 #[inline]
299 fn from(error: E) -> Self {
300 Error::Database(Box::new(error))
301 }
302}
303
304#[cfg(feature = "migrate")]
305impl From<crate::migrate::MigrateError> for Error {
306 #[inline]
307 fn from(error: crate::migrate::MigrateError) -> Self {
308 Error::Migrate(Box::new(error))
309 }
310}
311
312#[macro_export]
314macro_rules! err_protocol {
315 ($($fmt_args:tt)*) => {
316 $crate::error::Error::Protocol(
317 format!(
318 "{} ({}:{})",
319 format_args!($($fmt_args)*),
322 module_path!(),
323 line!(),
324 )
325 )
326 };
327}