sqlx_core_guts/postgres/
error.rs1use std::error::Error;
2use std::fmt::{self, Debug, Display, Formatter};
3
4use atoi::atoi;
5use smallvec::alloc::borrow::Cow;
6
7use crate::error::DatabaseError;
8use crate::postgres::message::{Notice, PgSeverity};
9
10pub struct PgDatabaseError(pub(crate) Notice);
12
13impl PgDatabaseError {
17 #[inline]
18 pub fn severity(&self) -> PgSeverity {
19 self.0.severity()
20 }
21
22 #[inline]
25 pub fn code(&self) -> &str {
26 self.0.code()
27 }
28
29 #[inline]
32 pub fn message(&self) -> &str {
33 self.0.message()
34 }
35
36 #[inline]
39 pub fn detail(&self) -> Option<&str> {
40 self.0.get(b'D')
41 }
42
43 #[inline]
47 pub fn hint(&self) -> Option<&str> {
48 self.0.get(b'H')
49 }
50
51 #[inline]
54 pub fn position(&self) -> Option<PgErrorPosition<'_>> {
55 self.0
56 .get_raw(b'P')
57 .and_then(atoi)
58 .map(PgErrorPosition::Original)
59 .or_else(|| {
60 let position = self.0.get_raw(b'p').and_then(atoi)?;
61 let query = self.0.get(b'q')?;
62
63 Some(PgErrorPosition::Internal { position, query })
64 })
65 }
66
67 pub fn r#where(&self) -> Option<&str> {
71 self.0.get(b'W')
72 }
73
74 pub fn schema(&self) -> Option<&str> {
77 self.0.get(b's')
78 }
79
80 pub fn table(&self) -> Option<&str> {
82 self.0.get(b't')
83 }
84
85 pub fn column(&self) -> Option<&str> {
87 self.0.get(b'c')
88 }
89
90 pub fn data_type(&self) -> Option<&str> {
92 self.0.get(b'd')
93 }
94
95 pub fn constraint(&self) -> Option<&str> {
99 self.0.get(b'n')
100 }
101
102 pub fn file(&self) -> Option<&str> {
104 self.0.get(b'F')
105 }
106
107 pub fn line(&self) -> Option<usize> {
109 self.0.get_raw(b'L').and_then(atoi)
110 }
111
112 pub fn routine(&self) -> Option<&str> {
114 self.0.get(b'R')
115 }
116}
117
118#[derive(Debug, Eq, PartialEq)]
119pub enum PgErrorPosition<'a> {
120 Original(usize),
122
123 Internal {
125 position: usize,
127
128 query: &'a str,
131 },
132}
133
134impl Debug for PgDatabaseError {
135 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
136 f.debug_struct("PgDatabaseError")
137 .field("severity", &self.severity())
138 .field("code", &self.code())
139 .field("message", &self.message())
140 .field("detail", &self.detail())
141 .field("hint", &self.hint())
142 .field("position", &self.position())
143 .field("where", &self.r#where())
144 .field("schema", &self.schema())
145 .field("table", &self.table())
146 .field("column", &self.column())
147 .field("data_type", &self.data_type())
148 .field("constraint", &self.constraint())
149 .field("file", &self.file())
150 .field("line", &self.line())
151 .field("routine", &self.routine())
152 .finish()
153 }
154}
155
156impl Display for PgDatabaseError {
157 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
158 f.write_str(self.message())
159 }
160}
161
162impl Error for PgDatabaseError {}
163
164impl DatabaseError for PgDatabaseError {
165 fn message(&self) -> &str {
166 self.message()
167 }
168
169 fn code(&self) -> Option<Cow<'_, str>> {
170 Some(Cow::Borrowed(self.code()))
171 }
172
173 #[doc(hidden)]
174 fn as_error(&self) -> &(dyn Error + Send + Sync + 'static) {
175 self
176 }
177
178 #[doc(hidden)]
179 fn as_error_mut(&mut self) -> &mut (dyn Error + Send + Sync + 'static) {
180 self
181 }
182
183 #[doc(hidden)]
184 fn into_error(self: Box<Self>) -> Box<dyn Error + Send + Sync + 'static> {
185 self
186 }
187
188 fn is_transient_in_connect_phase(&self) -> bool {
189 [
191 "53300",
195 "57P03",
198 ]
199 .contains(&self.code())
200 }
201
202 fn constraint(&self) -> Option<&str> {
203 self.constraint()
204 }
205}