1mod sql_state;
6
7pub use postgres_types::{WasNull, WrongType};
8
9use core::{
10 convert::Infallible,
11 fmt,
12 ops::{Deref, DerefMut},
13};
14
15use std::{backtrace::Backtrace, error, io};
16
17use fallible_iterator::FallibleIterator;
18
19use super::{from_sql::FromSqlError, protocol::message::backend::ErrorFields};
20
21pub use self::sql_state::SqlState;
22
23pub struct Error(Box<dyn error::Error + Send + Sync>);
38
39impl Error {
40 pub fn is_driver_down(&self) -> bool {
41 self.0.is::<DriverDown>() || self.0.is::<ClosedByDriver>()
42 }
43
44 pub(crate) fn todo() -> Self {
45 Self(Box::new(ToDo {
46 back_trace: Backtrace::capture(),
47 }))
48 }
49
50 pub(crate) fn driver_io(read: Option<io::Error>, write: Option<io::Error>) -> Self {
51 match (read, write) {
52 (Some(read), Some(write)) => Self::from(DriverIoErrorMulti { read, write }),
53 (Some(read), None) => Self::from(read),
54 (None, Some(write)) => Self::from(write),
55 _ => unreachable!("Driver must not report error when it doesn't produce any"),
56 }
57 }
58
59 #[cold]
60 #[inline(never)]
61 pub(crate) fn db(mut fields: ErrorFields<'_>) -> Error {
62 match DbError::parse(&mut fields) {
63 Ok(e) => Error::from(e),
64 Err(e) => Error::from(e),
65 }
66 }
67
68 pub(crate) fn unexpected() -> Self {
69 Self(Box::new(UnexpectedMessage {
70 back_trace: Backtrace::capture(),
71 }))
72 }
73}
74
75impl Deref for Error {
76 type Target = dyn error::Error + Send + Sync;
77
78 fn deref(&self) -> &Self::Target {
79 &*self.0
80 }
81}
82
83impl DerefMut for Error {
84 fn deref_mut(&mut self) -> &mut Self::Target {
85 &mut *self.0
86 }
87}
88
89impl fmt::Debug for Error {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 fmt::Debug::fmt(&self.0, f)
92 }
93}
94
95impl fmt::Display for Error {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 fmt::Display::fmt(&self.0, f)
98 }
99}
100
101impl error::Error for Error {
102 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
103 self.0.source()
104 }
105}
106
107macro_rules! from_impl {
108 ($i: ty) => {
109 impl From<$i> for Error {
110 fn from(e: $i) -> Self {
111 Self(Box::new(e))
112 }
113 }
114 };
115}
116
117#[derive(Debug)]
120pub struct ToDo {
121 back_trace: Backtrace,
122}
123
124impl fmt::Display for ToDo {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 write!(f, "WIP error type with thread backtrace: {}", self.back_trace)
127 }
128}
129
130impl error::Error for ToDo {}
131
132#[derive(Debug)]
136pub struct Completed;
137
138impl fmt::Display for Completed {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 f.write_str("Response has already finished. No more database response available")
141 }
142}
143
144impl error::Error for Completed {}
145
146from_impl!(Completed);
147
148#[derive(Default)]
184pub struct DriverDown;
185
186impl fmt::Debug for DriverDown {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 f.debug_struct("DriverDown").finish()
189 }
190}
191
192impl fmt::Display for DriverDown {
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 f.write_str("Client's Driver is dropped and unaccessible. Associated query has not been sent to database.")
195 }
196}
197
198impl error::Error for DriverDown {}
199
200from_impl!(DriverDown);
201
202#[derive(Debug)]
210pub struct ClosedByDriver;
211
212impl fmt::Display for ClosedByDriver {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 f.write_str("Reponse closed by Driver. No more data can be collected")
215 }
216}
217
218impl error::Error for ClosedByDriver {}
219
220from_impl!(ClosedByDriver);
221
222#[derive(Debug)]
224pub struct DriverIoErrorMulti {
225 read: io::Error,
226 write: io::Error,
227}
228
229impl fmt::Display for DriverIoErrorMulti {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(
232 f,
233 "Multiple IO error from driver {{ read error: {}, write error: {} }}",
234 self.read, self.write
235 )
236 }
237}
238
239impl error::Error for DriverIoErrorMulti {}
240
241from_impl!(DriverIoErrorMulti);
242
243pub struct InvalidColumnIndex(pub String);
244
245impl fmt::Debug for InvalidColumnIndex {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 f.debug_struct("InvalidColumnIndex").finish()
248 }
249}
250
251impl fmt::Display for InvalidColumnIndex {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 write!(f, "invalid column index: {}", self.0)
254 }
255}
256
257impl error::Error for InvalidColumnIndex {}
258
259from_impl!(InvalidColumnIndex);
260
261#[derive(Debug)]
262pub struct InvalidParamCount {
263 pub expected: usize,
264 pub params: usize,
265}
266
267impl fmt::Display for InvalidParamCount {
268 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 write!(
270 f,
271 "expected Statement bind to {} parameters but got {}.\r\n",
272 self.expected, self.params
273 )?;
274 f.write_str("note: consider use `Statement::bind` or check the parameter values count if already used")
275 }
276}
277
278impl error::Error for InvalidParamCount {}
279
280from_impl!(InvalidParamCount);
281
282impl From<Infallible> for Error {
283 fn from(e: Infallible) -> Self {
284 match e {}
285 }
286}
287
288from_impl!(io::Error);
289
290impl From<FromSqlError> for Error {
291 fn from(e: FromSqlError) -> Self {
292 Self(e)
293 }
294}
295
296#[derive(Debug)]
300pub enum ConfigError {
301 EmptyHost,
302 EmptyPort,
303 MissingUserName,
304 MissingPassWord,
305 WrongPassWord,
306}
307
308impl fmt::Display for ConfigError {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 f.write_str("Config error: ")?;
311 match self {
312 Self::EmptyHost => f.write_str("no available host name found"),
313 Self::EmptyPort => f.write_str("no available host port found"),
314 Self::MissingUserName => f.write_str("username is missing"),
315 Self::MissingPassWord => f.write_str("password is missing"),
316 Self::WrongPassWord => f.write_str("password is wrong"),
317 }
318 }
319}
320
321impl error::Error for ConfigError {}
322
323from_impl!(ConfigError);
324
325#[non_exhaustive]
326#[derive(Debug)]
327pub enum SystemError {
328 Unix,
329}
330
331impl fmt::Display for SystemError {
332 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333 match *self {
334 Self::Unix => f.write_str("unix")?,
335 }
336 f.write_str(" system is not available")
337 }
338}
339
340impl error::Error for SystemError {}
341
342from_impl!(SystemError);
343
344#[non_exhaustive]
345#[derive(Debug)]
346pub enum FeatureError {
347 Tls,
348 Quic,
349}
350
351impl fmt::Display for FeatureError {
352 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353 match *self {
354 Self::Tls => f.write_str("tls")?,
355 Self::Quic => f.write_str("quic")?,
356 }
357 f.write_str(" feature is not enabled")
358 }
359}
360
361impl error::Error for FeatureError {}
362
363from_impl!(FeatureError);
364
365#[derive(Debug, PartialEq, Eq)]
366pub enum RuntimeError {
367 RequireNoTokio,
368}
369
370impl fmt::Display for RuntimeError {
371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 match *self {
373 Self::RequireNoTokio => f.write_str("Tokio runtime detected. Must be called from outside of tokio"),
374 }
375 }
376}
377
378impl error::Error for RuntimeError {}
379
380from_impl!(RuntimeError);
381
382#[derive(Debug)]
385pub struct UnexpectedMessage {
386 back_trace: Backtrace,
387}
388
389impl fmt::Display for UnexpectedMessage {
390 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391 f.write_str("Unexpected message from database with stack trace:\r\n")?;
392 write!(f, "{}", self.back_trace)
393 }
394}
395
396impl error::Error for UnexpectedMessage {}
397
398#[cold]
399#[inline(never)]
400pub(crate) fn unexpected_eof_err() -> io::Error {
401 io::Error::new(
402 io::ErrorKind::UnexpectedEof,
403 "zero byte read. remote close connection unexpectedly",
404 )
405}
406
407from_impl!(WrongType);
408
409#[derive(Debug, Clone, PartialEq, Eq)]
411pub struct DbError {
412 severity: String,
413 parsed_severity: Option<Severity>,
414 code: SqlState,
415 message: String,
416 detail: Option<String>,
417 hint: Option<String>,
418 position: Option<ErrorPosition>,
419 where_: Option<String>,
420 schema: Option<String>,
421 table: Option<String>,
422 column: Option<String>,
423 datatype: Option<String>,
424 constraint: Option<String>,
425 file: Option<String>,
426 line: Option<u32>,
427 routine: Option<String>,
428}
429
430impl DbError {
431 fn parse(fields: &mut ErrorFields<'_>) -> io::Result<DbError> {
432 let mut severity = None;
433 let mut parsed_severity = None;
434 let mut code = None;
435 let mut message = None;
436 let mut detail = None;
437 let mut hint = None;
438 let mut normal_position = None;
439 let mut internal_position = None;
440 let mut internal_query = None;
441 let mut where_ = None;
442 let mut schema = None;
443 let mut table = None;
444 let mut column = None;
445 let mut datatype = None;
446 let mut constraint = None;
447 let mut file = None;
448 let mut line = None;
449 let mut routine = None;
450
451 while let Some(field) = fields.next()? {
452 let value = String::from_utf8_lossy(field.value_bytes());
453 match field.type_() {
454 b'S' => severity = Some(value.into_owned()),
455 b'C' => code = Some(SqlState::from_code(&value)),
456 b'M' => message = Some(value.into_owned()),
457 b'D' => detail = Some(value.into_owned()),
458 b'H' => hint = Some(value.into_owned()),
459 b'P' => {
460 normal_position = Some(value.parse::<u32>().map_err(|_| {
461 io::Error::new(io::ErrorKind::InvalidInput, "`P` field did not contain an integer")
462 })?);
463 }
464 b'p' => {
465 internal_position = Some(value.parse::<u32>().map_err(|_| {
466 io::Error::new(io::ErrorKind::InvalidInput, "`p` field did not contain an integer")
467 })?);
468 }
469 b'q' => internal_query = Some(value.into_owned()),
470 b'W' => where_ = Some(value.into_owned()),
471 b's' => schema = Some(value.into_owned()),
472 b't' => table = Some(value.into_owned()),
473 b'c' => column = Some(value.into_owned()),
474 b'd' => datatype = Some(value.into_owned()),
475 b'n' => constraint = Some(value.into_owned()),
476 b'F' => file = Some(value.into_owned()),
477 b'L' => {
478 line = Some(value.parse::<u32>().map_err(|_| {
479 io::Error::new(io::ErrorKind::InvalidInput, "`L` field did not contain an integer")
480 })?);
481 }
482 b'R' => routine = Some(value.into_owned()),
483 b'V' => {
484 parsed_severity = Some(Severity::from_str(&value).ok_or_else(|| {
485 io::Error::new(io::ErrorKind::InvalidInput, "`V` field contained an invalid value")
486 })?);
487 }
488 _ => {}
489 }
490 }
491
492 Ok(DbError {
493 severity: severity.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "`S` field missing"))?,
494 parsed_severity,
495 code: code.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "`C` field missing"))?,
496 message: message.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "`M` field missing"))?,
497 detail,
498 hint,
499 position: match normal_position {
500 Some(position) => Some(ErrorPosition::Original(position)),
501 None => match internal_position {
502 Some(position) => Some(ErrorPosition::Internal {
503 position,
504 query: internal_query.ok_or_else(|| {
505 io::Error::new(io::ErrorKind::InvalidInput, "`q` field missing but `p` field present")
506 })?,
507 }),
508 None => None,
509 },
510 },
511 where_,
512 schema,
513 table,
514 column,
515 datatype,
516 constraint,
517 file,
518 line,
519 routine,
520 })
521 }
522
523 pub fn severity(&self) -> &str {
527 &self.severity
528 }
529
530 pub fn parsed_severity(&self) -> Option<Severity> {
532 self.parsed_severity
533 }
534
535 pub fn code(&self) -> &SqlState {
537 &self.code
538 }
539
540 pub fn message(&self) -> &str {
544 &self.message
545 }
546
547 pub fn detail(&self) -> Option<&str> {
552 self.detail.as_deref()
553 }
554
555 pub fn hint(&self) -> Option<&str> {
561 self.hint.as_deref()
562 }
563
564 pub fn position(&self) -> Option<&ErrorPosition> {
567 self.position.as_ref()
568 }
569
570 pub fn where_(&self) -> Option<&str> {
576 self.where_.as_deref()
577 }
578
579 pub fn schema(&self) -> Option<&str> {
582 self.schema.as_deref()
583 }
584
585 pub fn table(&self) -> Option<&str> {
589 self.table.as_deref()
590 }
591
592 pub fn column(&self) -> Option<&str> {
598 self.column.as_deref()
599 }
600
601 pub fn datatype(&self) -> Option<&str> {
605 self.datatype.as_deref()
606 }
607
608 pub fn constraint(&self) -> Option<&str> {
615 self.constraint.as_deref()
616 }
617
618 pub fn file(&self) -> Option<&str> {
620 self.file.as_deref()
621 }
622
623 pub fn line(&self) -> Option<u32> {
626 self.line
627 }
628
629 pub fn routine(&self) -> Option<&str> {
631 self.routine.as_deref()
632 }
633}
634
635impl fmt::Display for DbError {
636 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
637 write!(fmt, "{}: {}", self.severity, self.message)?;
638 if let Some(detail) = &self.detail {
639 write!(fmt, "\nDETAIL: {detail}")?;
640 }
641 if let Some(hint) = &self.hint {
642 write!(fmt, "\nHINT: {hint}")?;
643 }
644 Ok(())
645 }
646}
647
648impl error::Error for DbError {}
649
650from_impl!(DbError);
651
652#[derive(Debug, Copy, Clone, PartialEq, Eq)]
654pub enum Severity {
655 Panic,
657 Fatal,
659 Error,
661 Warning,
663 Notice,
665 Debug,
667 Info,
669 Log,
671}
672
673impl fmt::Display for Severity {
674 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
675 let s = match *self {
676 Severity::Panic => "PANIC",
677 Severity::Fatal => "FATAL",
678 Severity::Error => "ERROR",
679 Severity::Warning => "WARNING",
680 Severity::Notice => "NOTICE",
681 Severity::Debug => "DEBUG",
682 Severity::Info => "INFO",
683 Severity::Log => "LOG",
684 };
685 fmt.write_str(s)
686 }
687}
688
689impl Severity {
690 fn from_str(s: &str) -> Option<Severity> {
691 match s {
692 "PANIC" => Some(Severity::Panic),
693 "FATAL" => Some(Severity::Fatal),
694 "ERROR" => Some(Severity::Error),
695 "WARNING" => Some(Severity::Warning),
696 "NOTICE" => Some(Severity::Notice),
697 "DEBUG" => Some(Severity::Debug),
698 "INFO" => Some(Severity::Info),
699 "LOG" => Some(Severity::Log),
700 _ => None,
701 }
702 }
703}
704
705#[derive(Clone, PartialEq, Eq, Debug)]
707pub enum ErrorPosition {
708 Original(u32),
710 Internal {
712 position: u32,
714 query: String,
716 },
717}