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