Skip to content

Commit 81fc578

Browse files
committed
Move ugh_privacy stuff to normal places
Use private traits to expose constructors internally
1 parent 0a4427e commit 81fc578

File tree

4 files changed

+242
-239
lines changed

4 files changed

+242
-239
lines changed

src/error.rs

Lines changed: 179 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,193 @@
1-
pub use ugh_privacy::DbError;
2-
31
use byteorder;
42
use phf;
53
use std::error;
64
use std::convert::From;
75
use std::fmt;
86
use std::io;
7+
use std::result;
8+
use std::collections::HashMap;
99

10-
use Result;
10+
use {Result, DbErrorNew};
1111
use types::Type;
1212

1313
include!(concat!(env!("OUT_DIR"), "/sqlstate.rs"));
1414

15+
/// A Postgres error or notice.
16+
#[derive(Clone, PartialEq, Eq, Debug)]
17+
pub struct DbError {
18+
severity: String,
19+
code: SqlState,
20+
message: String,
21+
detail: Option<String>,
22+
hint: Option<String>,
23+
position: Option<ErrorPosition>,
24+
where_: Option<String>,
25+
schema: Option<String>,
26+
table: Option<String>,
27+
column: Option<String>,
28+
datatype: Option<String>,
29+
constraint: Option<String>,
30+
file: String,
31+
line: u32,
32+
routine: String,
33+
}
34+
35+
impl DbErrorNew for DbError {
36+
fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()> {
37+
let mut map: HashMap<_, _> = fields.into_iter().collect();
38+
Ok(DbError {
39+
severity: try!(map.remove(&b'S').ok_or(())),
40+
code: SqlState::from_code(try!(map.remove(&b'C').ok_or(()))),
41+
message: try!(map.remove(&b'M').ok_or(())),
42+
detail: map.remove(&b'D'),
43+
hint: map.remove(&b'H'),
44+
position: match map.remove(&b'P') {
45+
Some(pos) => Some(ErrorPosition::Normal(try!(pos.parse().map_err(|_| ())))),
46+
None => match map.remove(&b'p') {
47+
Some(pos) => Some(ErrorPosition::Internal {
48+
position: try!(pos.parse().map_err(|_| ())),
49+
query: try!(map.remove(&b'q').ok_or(()))
50+
}),
51+
None => None
52+
}
53+
},
54+
where_: map.remove(&b'W'),
55+
schema: map.remove(&b's'),
56+
table: map.remove(&b't'),
57+
column: map.remove(&b'c'),
58+
datatype: map.remove(&b'd'),
59+
constraint: map.remove(&b'n'),
60+
file: try!(map.remove(&b'F').ok_or(())),
61+
line: try!(map.remove(&b'L').and_then(|l| l.parse().ok()).ok_or(())),
62+
routine: try!(map.remove(&b'R').ok_or(())),
63+
})
64+
}
65+
66+
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
67+
match DbError::new_raw(fields) {
68+
Ok(err) => Err(ConnectError::DbError(err)),
69+
Err(()) => Err(ConnectError::BadResponse),
70+
}
71+
}
72+
73+
fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
74+
match DbError::new_raw(fields) {
75+
Ok(err) => Err(Error::DbError(err)),
76+
Err(()) => Err(Error::BadResponse),
77+
}
78+
}
79+
}
80+
81+
impl DbError {
82+
/// The field contents are ERROR, FATAL, or PANIC (in an error message),
83+
/// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
84+
/// localized translation of one of these.
85+
pub fn severity(&self) -> &str {
86+
&self.severity
87+
}
88+
89+
/// The SQLSTATE code for the error.
90+
pub fn code(&self) -> &SqlState {
91+
&self.code
92+
}
93+
94+
/// The primary human-readable error message. This should be accurate but
95+
/// terse (typically one line).
96+
pub fn message(&self) -> &str {
97+
&self.message
98+
}
99+
100+
/// An optional secondary error message carrying more detail about the
101+
/// problem. Might run to multiple lines.
102+
pub fn detail(&self) -> Option<&str> {
103+
self.detail.as_ref().map(|s| &**s)
104+
}
105+
106+
/// An optional suggestion what to do about the problem. This is intended
107+
/// to differ from Detail in that it offers advice (potentially
108+
/// inappropriate) rather than hard facts. Might run to multiple lines.
109+
pub fn hint(&self) -> Option<&str> {
110+
self.hint.as_ref().map(|s| &**s)
111+
}
112+
113+
/// An optional error cursor position into either the original query string
114+
/// or an internally generated query.
115+
pub fn position(&self) -> Option<&ErrorPosition> {
116+
self.position.as_ref()
117+
}
118+
119+
/// An indication of the context in which the error occurred. Presently
120+
/// this includes a call stack traceback of active procedural language
121+
/// functions and internally-generated queries. The trace is one entry per
122+
/// line, most recent first.
123+
pub fn where_(&self) -> Option<&str> {
124+
self.where_.as_ref().map(|s| &**s)
125+
}
126+
127+
/// If the error was associated with a specific database object, the name
128+
/// of the schema containing that object, if any. (PostgreSQL 9.3+)
129+
pub fn schema(&self) -> Option<&str> {
130+
self.schema.as_ref().map(|s| &**s)
131+
}
132+
133+
/// If the error was associated with a specific table, the name of the
134+
/// table. (Refer to the schema name field for the name of the table's
135+
/// schema.) (PostgreSQL 9.3+)
136+
pub fn table(&self) -> Option<&str> {
137+
self.table.as_ref().map(|s| &**s)
138+
}
139+
140+
/// If the error was associated with a specific table column, the name of
141+
/// the column. (Refer to the schema and table name fields to identify the
142+
/// table.) (PostgreSQL 9.3+)
143+
pub fn column(&self) -> Option<&str> {
144+
self.column.as_ref().map(|s| &**s)
145+
}
146+
147+
/// If the error was associated with a specific data type, the name of the
148+
/// data type. (Refer to the schema name field for the name of the data
149+
/// type's schema.) (PostgreSQL 9.3+)
150+
pub fn datatype(&self) -> Option<&str> {
151+
self.datatype.as_ref().map(|s| &**s)
152+
}
153+
154+
/// If the error was associated with a specific constraint, the name of the
155+
/// constraint. Refer to fields listed above for the associated table or
156+
/// domain. (For this purpose, indexes are treated as constraints, even if
157+
/// they weren't created with constraint syntax.) (PostgreSQL 9.3+)
158+
pub fn constraint(&self) -> Option<&str> {
159+
self.constraint.as_ref().map(|s| &**s)
160+
}
161+
162+
/// The file name of the source-code location where the error was reported.
163+
pub fn file(&self) -> &str {
164+
&self.file
165+
}
166+
167+
/// The line number of the source-code location where the error was
168+
/// reported.
169+
pub fn line(&self) -> u32 {
170+
self.line
171+
}
172+
173+
/// The name of the source-code routine reporting the error.
174+
pub fn routine(&self) -> &str {
175+
&self.routine
176+
}
177+
}
178+
179+
impl fmt::Display for DbError {
180+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
181+
write!(fmt, "{}: {}", self.severity, self.message)
182+
}
183+
}
184+
185+
impl error::Error for DbError {
186+
fn description(&self) -> &str {
187+
&self.message
188+
}
189+
}
190+
15191
/// Reasons a new Postgres connection could fail.
16192
#[derive(Debug)]
17193
pub enum ConnectError {

src/lib.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ use std::path::PathBuf;
7878

7979
pub use error::{Error, ConnectError, SqlState, DbError, ErrorPosition};
8080
#[doc(inline)]
81-
pub use types::{Oid, Type, Kind, ToSql, FromSql, SessionInfo};
81+
pub use types::{Oid, Type, Other, Kind, ToSql, FromSql, SessionInfo};
8282
use io::{StreamWrapper, NegotiateSsl};
8383
use types::IsNull;
8484
#[doc(inline)]
@@ -95,7 +95,6 @@ mod macros;
9595
mod error;
9696
pub mod io;
9797
mod message;
98-
mod ugh_privacy;
9998
mod priv_io;
10099
mod url;
101100
mod util;
@@ -548,7 +547,7 @@ impl InnerConnection {
548547
conn.cancel_data.secret_key = secret_key;
549548
}
550549
ReadyForQuery { .. } => break,
551-
ErrorResponse { fields } => return ugh_privacy::dberror_new_connect(fields),
550+
ErrorResponse { fields } => return DbError::new_connect(fields),
552551
_ => return Err(ConnectError::BadResponse),
553552
}
554553
}
@@ -596,7 +595,7 @@ impl InnerConnection {
596595
debug_assert!(!self.desynchronized);
597596
match try_desync!(self, self.stream.read_message()) {
598597
NoticeResponse { fields } => {
599-
if let Ok(err) = ugh_privacy::dberror_new_raw(fields) {
598+
if let Ok(err) = DbError::new_raw(fields) {
600599
self.notice_handler.handle_notice(err);
601600
}
602601
Ok(None)
@@ -659,13 +658,13 @@ impl InnerConnection {
659658
| AuthenticationSCMCredential
660659
| AuthenticationGSS
661660
| AuthenticationSSPI => return Err(ConnectError::UnsupportedAuthentication),
662-
ErrorResponse { fields } => return ugh_privacy::dberror_new_connect(fields),
661+
ErrorResponse { fields } => return DbError::new_connect(fields),
663662
_ => return Err(ConnectError::BadResponse)
664663
}
665664

666665
match try!(self.read_message()) {
667666
AuthenticationOk => Ok(()),
668-
ErrorResponse { fields } => return ugh_privacy::dberror_new_connect(fields),
667+
ErrorResponse { fields } => return DbError::new_connect(fields),
669668
_ => return Err(ConnectError::BadResponse)
670669
}
671670
}
@@ -693,7 +692,7 @@ impl InnerConnection {
693692
ParseComplete => {}
694693
ErrorResponse { fields } => {
695694
try!(self.wait_for_ready());
696-
return ugh_privacy::dberror_new(fields);
695+
return DbError::new(fields);
697696
}
698697
_ => bad_response!(self),
699698
}
@@ -812,7 +811,7 @@ impl InnerConnection {
812811
Sync]));
813812
let resp = match try!(self.read_message()) {
814813
CloseComplete => Ok(()),
815-
ErrorResponse { fields } => ugh_privacy::dberror_new(fields),
814+
ErrorResponse { fields } => DbError::new(fields),
816815
_ => bad_response!(self)
817816
};
818817
try!(self.wait_for_ready());
@@ -851,7 +850,7 @@ impl InnerConnection {
851850
BindComplete => {}
852851
ErrorResponse { fields } => {
853852
try!(self.wait_for_ready());
854-
return ugh_privacy::dberror_new(fields);
853+
return DbError::new(fields);
855854
}
856855
_ => bad_response!(self)
857856
}
@@ -871,15 +870,15 @@ impl InnerConnection {
871870
}
872871
ErrorResponse { fields } => {
873872
try!(self.wait_for_ready());
874-
return ugh_privacy::dberror_new(fields);
873+
return DbError::new(fields);
875874
}
876875
_ => bad_response!(self)
877876
};
878877
match try!(self.read_message()) {
879878
CommandComplete { .. } => {}
880879
ErrorResponse { fields } => {
881880
try!(self.wait_for_ready());
882-
return ugh_privacy::dberror_new(fields);
881+
return DbError::new(fields);
883882
}
884883
_ => bad_response!(self)
885884
}
@@ -894,7 +893,7 @@ impl InnerConnection {
894893
}
895894
};
896895

897-
let type_ = Type::Other(Box::new(ugh_privacy::new_other(name, oid, kind)));
896+
let type_ = Type::Other(Box::new(Other::new(name, oid, kind)));
898897
self.unknown_types.insert(oid, type_.clone());
899898
Ok(type_)
900899
}
@@ -933,7 +932,7 @@ impl InnerConnection {
933932
}
934933
ErrorResponse { fields } => {
935934
try!(self.wait_for_ready());
936-
return ugh_privacy::dberror_new(fields);
935+
return DbError::new(fields);
937936
}
938937
_ => {}
939938
}
@@ -1466,7 +1465,7 @@ impl<'conn> Statement<'conn> {
14661465
BindComplete => Ok(()),
14671466
ErrorResponse { fields } => {
14681467
try!(conn.wait_for_ready());
1469-
ugh_privacy::dberror_new(fields)
1468+
DbError::new(fields)
14701469
}
14711470
_ => {
14721471
conn.desynchronized = true;
@@ -1527,7 +1526,7 @@ impl<'conn> Statement<'conn> {
15271526
DataRow { .. } => {}
15281527
ErrorResponse { fields } => {
15291528
try!(conn.wait_for_ready());
1530-
return ugh_privacy::dberror_new(fields);
1529+
return DbError::new(fields);
15311530
}
15321531
CommandComplete { tag } => {
15331532
num = util::parse_update_count(tag);
@@ -1683,7 +1682,7 @@ fn read_rows(conn: &mut InnerConnection, buf: &mut VecDeque<Vec<Option<Vec<u8>>>
16831682
DataRow { row } => buf.push_back(row),
16841683
ErrorResponse { fields } => {
16851684
try!(conn.wait_for_ready());
1686-
return ugh_privacy::dberror_new(fields);
1685+
return DbError::new(fields);
16871686
}
16881687
CopyInResponse { .. } => {
16891688
try!(conn.write_messages(&[
@@ -2133,7 +2132,7 @@ impl<'a> CopyInStatement<'a> {
21332132
BindComplete => {},
21342133
ErrorResponse { fields } => {
21352134
try!(conn.wait_for_ready());
2136-
return ugh_privacy::dberror_new(fields);
2135+
return DbError::new(fields);
21372136
}
21382137
_ => {
21392138
conn.desynchronized = true;
@@ -2210,7 +2209,7 @@ impl<'a> CopyInStatement<'a> {
22102209
CommandComplete { tag } => util::parse_update_count(tag),
22112210
ErrorResponse { fields } => {
22122211
try!(conn.wait_for_ready());
2213-
return ugh_privacy::dberror_new(fields);
2212+
return DbError::new(fields);
22142213
}
22152214
_ => {
22162215
conn.desynchronized = true;
@@ -2319,3 +2318,13 @@ impl<'a> GenericConnection for Transaction<'a> {
23192318
self.is_active()
23202319
}
23212320
}
2321+
2322+
trait OtherNew {
2323+
fn new(name: String, oid: Oid, kind: Kind) -> Other;
2324+
}
2325+
2326+
trait DbErrorNew {
2327+
fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()>;
2328+
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError>;
2329+
fn new<T>(fields: Vec<(u8, String)>) -> Result<T>;
2330+
}

0 commit comments

Comments
 (0)