1use std::fmt;
2
3pub type Result<T> = std::result::Result<T, Error>;
5
6#[derive(Debug, thiserror::Error)]
8pub enum Error {
9 #[error("io error: {0}")]
11 Io(#[from] std::io::Error),
12
13 #[error("protocol error: {0}")]
15 Protocol(String),
16
17 #[error("{0}")]
19 Server(Box<ServerError>),
20
21 #[error("authentication failed: {0}")]
23 Auth(String),
24
25 #[error("tls error: {0}")]
27 Tls(String),
28
29 #[error("pool error: {0}")]
31 Pool(String),
32
33 #[error("config error: {0}")]
35 Config(String),
36
37 #[error("encode error: {0}")]
39 Encode(String),
40
41 #[error("decode error: {0}")]
43 Decode(String),
44
45 #[error("column not found: {0}")]
47 ColumnNotFound(String),
48
49 #[error("column index {index} out of bounds (row has {count} columns)")]
51 ColumnIndex { index: usize, count: usize },
52
53 #[error("unexpected null in column {0}")]
55 UnexpectedNull(usize),
56
57 #[error("timeout: {0}")]
59 Timeout(String),
60
61 #[error("connection closed")]
63 ConnectionClosed,
64
65 #[error("copy error: {0}")]
67 Copy(String),
68
69 #[error("transaction already completed")]
71 TransactionCompleted,
72
73 #[error("all hosts failed: {0}")]
75 AllHostsFailed(String),
76
77 #[error("wrong session attributes: {0}")]
79 WrongSessionAttrs(String),
80}
81
82#[derive(Debug, Clone)]
84pub struct ServerError {
85 pub severity: String,
86 pub code: String,
87 pub message: String,
88 pub detail: Option<String>,
89 pub hint: Option<String>,
90 pub position: Option<u32>,
91}
92
93impl fmt::Display for ServerError {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 write!(
96 f,
97 "{}: {} (SQLSTATE {})",
98 self.severity, self.message, self.code
99 )
100 }
101}
102
103impl Error {
104 pub fn code(&self) -> Option<&str> {
106 match self {
107 Error::Server(e) => Some(&e.code),
108 _ => None,
109 }
110 }
111
112 pub fn server_error(&self) -> Option<&ServerError> {
114 match self {
115 Error::Server(e) => Some(e),
116 _ => None,
117 }
118 }
119
120 pub fn is_unique_violation(&self) -> bool {
122 self.code() == Some("23505")
123 }
124
125 pub fn is_foreign_key_violation(&self) -> bool {
127 self.code() == Some("23503")
128 }
129
130 pub fn is_fatal(&self) -> bool {
132 matches!(self, Error::Io(_) | Error::ConnectionClosed | Error::Tls(_))
133 }
134}
135
136impl Error {
137 pub(crate) fn protocol(msg: impl Into<String>) -> Self {
139 Error::Protocol(msg.into())
140 }
141
142 pub(crate) fn server(
144 severity: String,
145 code: String,
146 message: String,
147 detail: Option<String>,
148 hint: Option<String>,
149 position: Option<u32>,
150 ) -> Self {
151 Error::Server(Box::new(ServerError {
152 severity,
153 code,
154 message,
155 detail,
156 hint,
157 position,
158 }))
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum Severity {
165 Error,
166 Fatal,
167 Panic,
168 Warning,
169 Notice,
170 Debug,
171 Info,
172 Log,
173}
174
175impl fmt::Display for Severity {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 match self {
178 Severity::Error => write!(f, "ERROR"),
179 Severity::Fatal => write!(f, "FATAL"),
180 Severity::Panic => write!(f, "PANIC"),
181 Severity::Warning => write!(f, "WARNING"),
182 Severity::Notice => write!(f, "NOTICE"),
183 Severity::Debug => write!(f, "DEBUG"),
184 Severity::Info => write!(f, "INFO"),
185 Severity::Log => write!(f, "LOG"),
186 }
187 }
188}