1
- pub use ugh_privacy :: DbError ;
1
+ //! Error types.
2
2
3
3
use byteorder;
4
- use openssl:: ssl:: error:: SslError ;
5
4
use phf;
6
5
use std:: error;
7
6
use std:: convert:: From ;
8
7
use std:: fmt;
9
8
use std:: io;
9
+ use std:: result;
10
+ use std:: collections:: HashMap ;
10
11
11
- use Result ;
12
+ use { Result , DbErrorNew } ;
12
13
use types:: Type ;
13
14
14
15
include ! ( concat!( env!( "OUT_DIR" ) , "/sqlstate.rs" ) ) ;
15
16
17
+ /// A Postgres error or notice.
18
+ #[ derive( Clone , PartialEq , Eq , Debug ) ]
19
+ 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 => match map. remove ( & b'p' ) {
49
+ Some ( pos) => Some ( ErrorPosition :: Internal {
50
+ position : try!( pos. parse ( ) . map_err ( |_| ( ) ) ) ,
51
+ query : try!( map. remove ( & b'q' ) . ok_or ( ( ) ) )
52
+ } ) ,
53
+ None => None
54
+ }
55
+ } ,
56
+ where_ : map. remove ( & b'W' ) ,
57
+ schema : map. remove ( & b's' ) ,
58
+ table : map. remove ( & b't' ) ,
59
+ column : map. remove ( & b'c' ) ,
60
+ datatype : map. remove ( & b'd' ) ,
61
+ constraint : map. remove ( & b'n' ) ,
62
+ file : try!( map. remove ( & b'F' ) . ok_or ( ( ) ) ) ,
63
+ line : try!( map. remove ( & b'L' ) . and_then ( |l| l. parse ( ) . ok ( ) ) . ok_or ( ( ) ) ) ,
64
+ routine : try!( map. remove ( & b'R' ) . ok_or ( ( ) ) ) ,
65
+ } )
66
+ }
67
+
68
+ fn new_connect < T > ( fields : Vec < ( u8 , String ) > ) -> result:: Result < T , ConnectError > {
69
+ match DbError :: new_raw ( fields) {
70
+ Ok ( err) => Err ( ConnectError :: DbError ( err) ) ,
71
+ Err ( ( ) ) => Err ( ConnectError :: IoError ( :: bad_response ( ) ) ) ,
72
+ }
73
+ }
74
+
75
+ fn new < T > ( fields : Vec < ( u8 , String ) > ) -> Result < T > {
76
+ match DbError :: new_raw ( fields) {
77
+ Ok ( err) => Err ( Error :: DbError ( err) ) ,
78
+ Err ( ( ) ) => Err ( Error :: IoError ( :: bad_response ( ) ) ) ,
79
+ }
80
+ }
81
+ }
82
+
83
+ impl DbError {
84
+ /// The field contents are ERROR, FATAL, or PANIC (in an error message),
85
+ /// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
86
+ /// localized translation of one of these.
87
+ pub fn severity ( & self ) -> & str {
88
+ & self . severity
89
+ }
90
+
91
+ /// The SQLSTATE code for the error.
92
+ pub fn code ( & self ) -> & SqlState {
93
+ & self . code
94
+ }
95
+
96
+ /// The primary human-readable error message. This should be accurate but
97
+ /// terse (typically one line).
98
+ pub fn message ( & self ) -> & str {
99
+ & self . message
100
+ }
101
+
102
+ /// An optional secondary error message carrying more detail about the
103
+ /// problem. Might run to multiple lines.
104
+ pub fn detail ( & self ) -> Option < & str > {
105
+ self . detail . as_ref ( ) . map ( |s| & * * s)
106
+ }
107
+
108
+ /// An optional suggestion what to do about the problem. This is intended
109
+ /// to differ from Detail in that it offers advice (potentially
110
+ /// inappropriate) rather than hard facts. Might run to multiple lines.
111
+ pub fn hint ( & self ) -> Option < & str > {
112
+ self . hint . as_ref ( ) . map ( |s| & * * s)
113
+ }
114
+
115
+ /// An optional error cursor position into either the original query string
116
+ /// or an internally generated query.
117
+ pub fn position ( & self ) -> Option < & ErrorPosition > {
118
+ self . position . as_ref ( )
119
+ }
120
+
121
+ /// An indication of the context in which the error occurred. Presently
122
+ /// this includes a call stack traceback of active procedural language
123
+ /// functions and internally-generated queries. The trace is one entry per
124
+ /// line, most recent first.
125
+ pub fn where_ ( & self ) -> Option < & str > {
126
+ self . where_ . as_ref ( ) . map ( |s| & * * s)
127
+ }
128
+
129
+ /// If the error was associated with a specific database object, the name
130
+ /// of the schema containing that object, if any. (PostgreSQL 9.3+)
131
+ pub fn schema ( & self ) -> Option < & str > {
132
+ self . schema . as_ref ( ) . map ( |s| & * * s)
133
+ }
134
+
135
+ /// If the error was associated with a specific table, the name of the
136
+ /// table. (Refer to the schema name field for the name of the table's
137
+ /// schema.) (PostgreSQL 9.3+)
138
+ pub fn table ( & self ) -> Option < & str > {
139
+ self . table . as_ref ( ) . map ( |s| & * * s)
140
+ }
141
+
142
+ /// If the error was associated with a specific table column, the name of
143
+ /// the column. (Refer to the schema and table name fields to identify the
144
+ /// table.) (PostgreSQL 9.3+)
145
+ pub fn column ( & self ) -> Option < & str > {
146
+ self . column . as_ref ( ) . map ( |s| & * * s)
147
+ }
148
+
149
+ /// If the error was associated with a specific data type, the name of the
150
+ /// data type. (Refer to the schema name field for the name of the data
151
+ /// type's schema.) (PostgreSQL 9.3+)
152
+ pub fn datatype ( & self ) -> Option < & str > {
153
+ self . datatype . as_ref ( ) . map ( |s| & * * s)
154
+ }
155
+
156
+ /// If the error was associated with a specific constraint, the name of the
157
+ /// constraint. Refer to fields listed above for the associated table or
158
+ /// domain. (For this purpose, indexes are treated as constraints, even if
159
+ /// they weren't created with constraint syntax.) (PostgreSQL 9.3+)
160
+ pub fn constraint ( & self ) -> Option < & str > {
161
+ self . constraint . as_ref ( ) . map ( |s| & * * s)
162
+ }
163
+
164
+ /// The file name of the source-code location where the error was reported.
165
+ pub fn file ( & self ) -> & str {
166
+ & self . file
167
+ }
168
+
169
+ /// The line number of the source-code location where the error was
170
+ /// reported.
171
+ pub fn line ( & self ) -> u32 {
172
+ self . line
173
+ }
174
+
175
+ /// The name of the source-code routine reporting the error.
176
+ pub fn routine ( & self ) -> & str {
177
+ & self . routine
178
+ }
179
+ }
180
+
181
+ impl fmt:: Display for DbError {
182
+ fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> fmt:: Result {
183
+ write ! ( fmt, "{}: {}" , self . severity, self . message)
184
+ }
185
+ }
186
+
187
+ impl error:: Error for DbError {
188
+ fn description ( & self ) -> & str {
189
+ & self . message
190
+ }
191
+ }
192
+
16
193
/// Reasons a new Postgres connection could fail.
17
194
#[ derive( Debug ) ]
18
195
pub enum ConnectError {
@@ -30,11 +207,9 @@ pub enum ConnectError {
30
207
/// The Postgres server does not support SSL encryption.
31
208
NoSslSupport ,
32
209
/// There was an error initializing the SSL session.
33
- SslError ( SslError ) ,
210
+ SslError ( Box < error :: Error + Sync + Send > ) ,
34
211
/// There was an error communicating with the server.
35
212
IoError ( io:: Error ) ,
36
- /// The server sent an unexpected response.
37
- BadResponse ,
38
213
}
39
214
40
215
impl fmt:: Display for ConnectError {
@@ -60,14 +235,13 @@ impl error::Error for ConnectError {
60
235
ConnectError :: NoSslSupport => "The server does not support SSL" ,
61
236
ConnectError :: SslError ( _) => "Error initiating SSL session" ,
62
237
ConnectError :: IoError ( _) => "Error communicating with server" ,
63
- ConnectError :: BadResponse => "The server returned an unexpected response" ,
64
238
}
65
239
}
66
240
67
241
fn cause ( & self ) -> Option < & error:: Error > {
68
242
match * self {
69
243
ConnectError :: DbError ( ref err) => Some ( err) ,
70
- ConnectError :: SslError ( ref err) => Some ( err) ,
244
+ ConnectError :: SslError ( ref err) => Some ( & * * err) ,
71
245
ConnectError :: IoError ( ref err) => Some ( err) ,
72
246
_ => None
73
247
}
@@ -86,12 +260,6 @@ impl From<DbError> for ConnectError {
86
260
}
87
261
}
88
262
89
- impl From < SslError > for ConnectError {
90
- fn from ( err : SslError ) -> ConnectError {
91
- ConnectError :: SslError ( err)
92
- }
93
- }
94
-
95
263
impl From < byteorder:: Error > for ConnectError {
96
264
fn from ( err : byteorder:: Error ) -> ConnectError {
97
265
ConnectError :: IoError ( From :: from ( err) )
@@ -119,18 +287,13 @@ pub enum Error {
119
287
DbError ( DbError ) ,
120
288
/// An error communicating with the Postgres server.
121
289
IoError ( io:: Error ) ,
122
- /// The communication channel with the Postgres server has desynchronized
123
- /// due to an earlier communications error.
124
- StreamDesynchronized ,
125
290
/// An attempt was made to convert between incompatible Rust and Postgres
126
291
/// types.
127
292
WrongType ( Type ) ,
128
293
/// An attempt was made to read from a column that does not exist.
129
294
InvalidColumn ,
130
- /// A value was NULL but converted to a non-nullable Rust type.
131
- WasNull ,
132
- /// The server returned an unexpected response.
133
- BadResponse ,
295
+ /// An error converting between Postgres and Rust types.
296
+ Conversion ( Box < error:: Error +Sync +Send > ) ,
134
297
}
135
298
136
299
impl fmt:: Display for Error {
@@ -148,20 +311,17 @@ impl error::Error for Error {
148
311
match * self {
149
312
Error :: DbError ( _) => "An error reported by the Postgres server" ,
150
313
Error :: IoError ( _) => "An error communicating with the Postgres server" ,
151
- Error :: StreamDesynchronized => {
152
- "Communication with the server has desynchronized due to an earlier IO error"
153
- }
154
314
Error :: WrongType ( _) => "Unexpected type" ,
155
315
Error :: InvalidColumn => "Invalid column" ,
156
- Error :: WasNull => "The value was NULL" ,
157
- Error :: BadResponse => "The server returned an unexpected response" ,
316
+ Error :: Conversion ( _) => "An error converting between Postgres and Rust types" ,
158
317
}
159
318
}
160
319
161
320
fn cause ( & self ) -> Option < & error:: Error > {
162
321
match * self {
163
322
Error :: DbError ( ref err) => Some ( err) ,
164
323
Error :: IoError ( ref err) => Some ( err) ,
324
+ Error :: Conversion ( ref err) => Some ( & * * err) ,
165
325
_ => None
166
326
}
167
327
}
0 commit comments