Skip to content

Commit 8fac512

Browse files
committed
Make DbError fields public
All of them are directly exposed via accessors and the internal representation is never realistically going to change. A single private field allows for expansion in the future.
1 parent 3b202e6 commit 8fac512

3 files changed

Lines changed: 81 additions & 126 deletions

File tree

src/error.rs

Lines changed: 67 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -17,168 +17,123 @@ include!(concat!(env!("OUT_DIR"), "/sqlstate.rs"));
1717
/// A Postgres error or notice.
1818
#[derive(Clone, PartialEq, Eq, Debug)]
1919
pub struct DbError {
20-
severity: String,
21-
code: SqlState,
22-
message: String,
23-
detail: Option<String>,
24-
hint: Option<String>,
25-
position: Option<ErrorPosition>,
26-
where_: Option<String>,
27-
schema: Option<String>,
28-
table: Option<String>,
29-
column: Option<String>,
30-
datatype: Option<String>,
31-
constraint: Option<String>,
32-
file: String,
33-
line: u32,
34-
routine: String,
35-
}
36-
37-
impl DbErrorNew for DbError {
38-
fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()> {
39-
let mut map: HashMap<_, _> = fields.into_iter().collect();
40-
Ok(DbError {
41-
severity: try!(map.remove(&b'S').ok_or(())),
42-
code: SqlState::from_code(try!(map.remove(&b'C').ok_or(()))),
43-
message: try!(map.remove(&b'M').ok_or(())),
44-
detail: map.remove(&b'D'),
45-
hint: map.remove(&b'H'),
46-
position: match map.remove(&b'P') {
47-
Some(pos) => Some(ErrorPosition::Normal(try!(pos.parse().map_err(|_| ())))),
48-
None => {
49-
match map.remove(&b'p') {
50-
Some(pos) => {
51-
Some(ErrorPosition::Internal {
52-
position: try!(pos.parse().map_err(|_| ())),
53-
query: try!(map.remove(&b'q').ok_or(())),
54-
})
55-
}
56-
None => None,
57-
}
58-
}
59-
},
60-
where_: map.remove(&b'W'),
61-
schema: map.remove(&b's'),
62-
table: map.remove(&b't'),
63-
column: map.remove(&b'c'),
64-
datatype: map.remove(&b'd'),
65-
constraint: map.remove(&b'n'),
66-
file: try!(map.remove(&b'F').ok_or(())),
67-
line: try!(map.remove(&b'L').and_then(|l| l.parse().ok()).ok_or(())),
68-
routine: try!(map.remove(&b'R').ok_or(())),
69-
})
70-
}
71-
72-
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
73-
match DbError::new_raw(fields) {
74-
Ok(err) => Err(ConnectError::DbError(Box::new(err))),
75-
Err(()) => Err(ConnectError::IoError(::bad_response())),
76-
}
77-
}
78-
79-
fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
80-
match DbError::new_raw(fields) {
81-
Ok(err) => Err(Error::DbError(Box::new(err))),
82-
Err(()) => Err(Error::IoError(::bad_response())),
83-
}
84-
}
85-
}
86-
87-
impl DbError {
8820
/// The field contents are ERROR, FATAL, or PANIC (in an error message),
8921
/// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
9022
/// localized translation of one of these.
91-
pub fn severity(&self) -> &str {
92-
&self.severity
93-
}
23+
pub severity: String,
9424

9525
/// The SQLSTATE code for the error.
96-
pub fn code(&self) -> &SqlState {
97-
&self.code
98-
}
26+
pub code: SqlState,
9927

10028
/// The primary human-readable error message. This should be accurate but
10129
/// terse (typically one line).
102-
pub fn message(&self) -> &str {
103-
&self.message
104-
}
30+
pub message: String,
10531

10632
/// An optional secondary error message carrying more detail about the
10733
/// problem. Might run to multiple lines.
108-
pub fn detail(&self) -> Option<&str> {
109-
self.detail.as_ref().map(|s| &**s)
110-
}
34+
pub detail: Option<String>,
11135

11236
/// An optional suggestion what to do about the problem. This is intended
11337
/// to differ from Detail in that it offers advice (potentially
11438
/// inappropriate) rather than hard facts. Might run to multiple lines.
115-
pub fn hint(&self) -> Option<&str> {
116-
self.hint.as_ref().map(|s| &**s)
117-
}
39+
pub hint: Option<String>,
11840

11941
/// An optional error cursor position into either the original query string
12042
/// or an internally generated query.
121-
pub fn position(&self) -> Option<&ErrorPosition> {
122-
self.position.as_ref()
123-
}
43+
pub position: Option<ErrorPosition>,
12444

12545
/// An indication of the context in which the error occurred. Presently
12646
/// this includes a call stack traceback of active procedural language
12747
/// functions and internally-generated queries. The trace is one entry per
12848
/// line, most recent first.
129-
pub fn where_(&self) -> Option<&str> {
130-
self.where_.as_ref().map(|s| &**s)
131-
}
49+
pub where_: Option<String>,
13250

13351
/// If the error was associated with a specific database object, the name
13452
/// of the schema containing that object, if any. (PostgreSQL 9.3+)
135-
pub fn schema(&self) -> Option<&str> {
136-
self.schema.as_ref().map(|s| &**s)
137-
}
53+
pub schema: Option<String>,
13854

13955
/// If the error was associated with a specific table, the name of the
14056
/// table. (Refer to the schema name field for the name of the table's
14157
/// schema.) (PostgreSQL 9.3+)
142-
pub fn table(&self) -> Option<&str> {
143-
self.table.as_ref().map(|s| &**s)
144-
}
58+
pub table: Option<String>,
14559

14660
/// If the error was associated with a specific table column, the name of
14761
/// the column. (Refer to the schema and table name fields to identify the
14862
/// table.) (PostgreSQL 9.3+)
149-
pub fn column(&self) -> Option<&str> {
150-
self.column.as_ref().map(|s| &**s)
151-
}
63+
pub column: Option<String>,
15264

15365
/// If the error was associated with a specific data type, the name of the
15466
/// data type. (Refer to the schema name field for the name of the data
15567
/// type's schema.) (PostgreSQL 9.3+)
156-
pub fn datatype(&self) -> Option<&str> {
157-
self.datatype.as_ref().map(|s| &**s)
158-
}
68+
pub datatype: Option<String>,
15969

16070
/// If the error was associated with a specific constraint, the name of the
16171
/// constraint. Refer to fields listed above for the associated table or
16272
/// domain. (For this purpose, indexes are treated as constraints, even if
16373
/// they weren't created with constraint syntax.) (PostgreSQL 9.3+)
164-
pub fn constraint(&self) -> Option<&str> {
165-
self.constraint.as_ref().map(|s| &**s)
166-
}
74+
pub constraint: Option<String>,
16775

16876
/// The file name of the source-code location where the error was reported.
169-
pub fn file(&self) -> &str {
170-
&self.file
171-
}
77+
pub file: String,
17278

17379
/// The line number of the source-code location where the error was
17480
/// reported.
175-
pub fn line(&self) -> u32 {
176-
self.line
177-
}
81+
pub line: u32,
17882

17983
/// The name of the source-code routine reporting the error.
180-
pub fn routine(&self) -> &str {
181-
&self.routine
84+
pub routine: String,
85+
86+
_p: (),
87+
}
88+
89+
impl DbErrorNew for DbError {
90+
fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()> {
91+
let mut map: HashMap<_, _> = fields.into_iter().collect();
92+
Ok(DbError {
93+
severity: try!(map.remove(&b'S').ok_or(())),
94+
code: SqlState::from_code(try!(map.remove(&b'C').ok_or(()))),
95+
message: try!(map.remove(&b'M').ok_or(())),
96+
detail: map.remove(&b'D'),
97+
hint: map.remove(&b'H'),
98+
position: match map.remove(&b'P') {
99+
Some(pos) => Some(ErrorPosition::Normal(try!(pos.parse().map_err(|_| ())))),
100+
None => {
101+
match map.remove(&b'p') {
102+
Some(pos) => {
103+
Some(ErrorPosition::Internal {
104+
position: try!(pos.parse().map_err(|_| ())),
105+
query: try!(map.remove(&b'q').ok_or(())),
106+
})
107+
}
108+
None => None,
109+
}
110+
}
111+
},
112+
where_: map.remove(&b'W'),
113+
schema: map.remove(&b's'),
114+
table: map.remove(&b't'),
115+
column: map.remove(&b'c'),
116+
datatype: map.remove(&b'd'),
117+
constraint: map.remove(&b'n'),
118+
file: try!(map.remove(&b'F').ok_or(())),
119+
line: try!(map.remove(&b'L').and_then(|l| l.parse().ok()).ok_or(())),
120+
routine: try!(map.remove(&b'R').ok_or(())),
121+
_p: (),
122+
})
123+
}
124+
125+
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
126+
match DbError::new_raw(fields) {
127+
Ok(err) => Err(ConnectError::DbError(Box::new(err))),
128+
Err(()) => Err(ConnectError::IoError(::bad_response())),
129+
}
130+
}
131+
132+
fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
133+
match DbError::new_raw(fields) {
134+
Ok(err) => Err(Error::DbError(Box::new(err))),
135+
Err(()) => Err(Error::IoError(::bad_response())),
136+
}
182137
}
183138
}
184139

src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ pub struct LoggingNoticeHandler;
229229

230230
impl HandleNotice for LoggingNoticeHandler {
231231
fn handle_notice(&mut self, notice: DbError) {
232-
info!("{}: {}", notice.severity(), notice.message());
232+
info!("{}: {}", notice.severity, notice.message);
233233
}
234234
}
235235

@@ -474,8 +474,8 @@ impl InnerConnection {
474474
WHERE t.oid = $1") {
475475
Ok(..) => return Ok(()),
476476
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
477-
// Range types weren't added until Postgres 9.2, so pg_range may not exist
478-
Err(Error::DbError(ref e)) if e.code() == &SqlState::UndefinedTable => {}
477+
// Range types weren't added until Postgres 9.2, so pg_range may not exist
478+
Err(Error::DbError(ref e)) if e.code == SqlState::UndefinedTable => {}
479479
Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)),
480480
_ => unreachable!(),
481481
}

tests/test.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn test_prepare_err() {
5656
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
5757
let stmt = conn.prepare("invalid sql database");
5858
match stmt {
59-
Err(Error::DbError(ref e)) if e.code() == &SyntaxError && e.position() == Some(&Normal(1)) => {}
59+
Err(Error::DbError(ref e)) if e.code == SyntaxError && e.position == Some(Normal(1)) => {}
6060
Err(e) => panic!("Unexpected result {:?}", e),
6161
_ => panic!("Unexpected result"),
6262
}
@@ -65,7 +65,7 @@ fn test_prepare_err() {
6565
#[test]
6666
fn test_unknown_database() {
6767
match Connection::connect("postgres://postgres@localhost/asdf", SslMode::None) {
68-
Err(ConnectError::DbError(ref e)) if e.code() == &InvalidCatalogName => {}
68+
Err(ConnectError::DbError(ref e)) if e.code == InvalidCatalogName => {}
6969
Err(resp) => panic!("Unexpected result {:?}", resp),
7070
_ => panic!("Unexpected result"),
7171
}
@@ -339,7 +339,7 @@ fn test_batch_execute_error() {
339339

340340
let stmt = conn.prepare("SELECT * FROM foo ORDER BY id");
341341
match stmt {
342-
Err(Error::DbError(ref e)) if e.code() == &UndefinedTable => {}
342+
Err(Error::DbError(ref e)) if e.code == UndefinedTable => {}
343343
Err(e) => panic!("unexpected error {:?}", e),
344344
_ => panic!("unexpected success"),
345345
}
@@ -382,7 +382,7 @@ FROM (SELECT gs.i
382382
ORDER BY gs.i
383383
LIMIT 2) ss"));
384384
match stmt.query(&[]) {
385-
Err(Error::DbError(ref e)) if e.code() == &CardinalityViolation => {}
385+
Err(Error::DbError(ref e)) if e.code == CardinalityViolation => {}
386386
Err(err) => panic!("Unexpected error {:?}", err),
387387
Ok(_) => panic!("Expected failure"),
388388
};
@@ -532,7 +532,7 @@ fn test_custom_notice_handler() {
532532

533533
impl HandleNotice for Handler {
534534
fn handle_notice(&mut self, notice: DbError) {
535-
assert_eq!("note", notice.message());
535+
assert_eq!("note", notice.message);
536536
unsafe { count += 1; }
537537
}
538538
}
@@ -648,7 +648,7 @@ fn test_cancel_query() {
648648
});
649649

650650
match conn.execute("SELECT pg_sleep(10)", &[]) {
651-
Err(Error::DbError(ref e)) if e.code() == &QueryCanceled => {}
651+
Err(Error::DbError(ref e)) if e.code == QueryCanceled => {}
652652
Err(res) => panic!("Unexpected result {:?}", res),
653653
_ => panic!("Unexpected result"),
654654
}
@@ -708,7 +708,7 @@ fn test_plaintext_pass_no_pass() {
708708
fn test_plaintext_pass_wrong_pass() {
709709
let ret = Connection::connect("postgres://pass_user:asdf@localhost/postgres", SslMode::None);
710710
match ret {
711-
Err(ConnectError::DbError(ref e)) if e.code() == &InvalidPassword => {}
711+
Err(ConnectError::DbError(ref e)) if e.code == InvalidPassword => {}
712712
Err(err) => panic!("Unexpected error {:?}", err),
713713
_ => panic!("Expected error")
714714
}
@@ -733,7 +733,7 @@ fn test_md5_pass_no_pass() {
733733
fn test_md5_pass_wrong_pass() {
734734
let ret = Connection::connect("postgres://md5_user:asdf@localhost/postgres", SslMode::None);
735735
match ret {
736-
Err(ConnectError::DbError(ref e)) if e.code() == &InvalidPassword => {}
736+
Err(ConnectError::DbError(ref e)) if e.code == InvalidPassword => {}
737737
Err(err) => panic!("Unexpected error {:?}", err),
738738
_ => panic!("Expected error")
739739
}
@@ -745,12 +745,12 @@ fn test_execute_copy_from_err() {
745745
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]));
746746
let stmt = or_panic!(conn.prepare("COPY foo (id) FROM STDIN"));
747747
match stmt.execute(&[]) {
748-
Err(Error::DbError(ref err)) if err.message().contains("COPY") => {}
748+
Err(Error::DbError(ref err)) if err.message.contains("COPY") => {}
749749
Err(err) => panic!("Unexpected error {:?}", err),
750750
_ => panic!("Expected error"),
751751
}
752752
match stmt.query(&[]) {
753-
Err(Error::DbError(ref err)) if err.message().contains("COPY") => {}
753+
Err(Error::DbError(ref err)) if err.message.contains("COPY") => {}
754754
Err(err) => panic!("Unexpected error {:?}", err),
755755
_ => panic!("Expected error"),
756756
};
@@ -761,7 +761,7 @@ fn test_batch_execute_copy_from_err() {
761761
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None));
762762
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]));
763763
match conn.batch_execute("COPY foo (id) FROM STDIN") {
764-
Err(Error::DbError(ref err)) if err.message().contains("COPY") => {}
764+
Err(Error::DbError(ref err)) if err.message.contains("COPY") => {}
765765
Err(err) => panic!("Unexpected error {:?}", err),
766766
_ => panic!("Expected error"),
767767
}

0 commit comments

Comments
 (0)