1- pub use ugh_privacy :: DbError ;
1+ //! Error types.
22
33use byteorder;
4- use openssl:: ssl:: error:: SslError ;
54use phf;
65use std:: error;
76use std:: convert:: From ;
87use std:: fmt;
98use std:: io;
9+ use std:: result;
10+ use std:: collections:: HashMap ;
1011
11- use Result ;
12+ use { Result , DbErrorNew } ;
1213use types:: Type ;
1314
1415include ! ( concat!( env!( "OUT_DIR" ) , "/sqlstate.rs" ) ) ;
1516
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+
16193/// Reasons a new Postgres connection could fail.
17194#[ derive( Debug ) ]
18195pub enum ConnectError {
@@ -30,11 +207,9 @@ pub enum ConnectError {
30207 /// The Postgres server does not support SSL encryption.
31208 NoSslSupport ,
32209 /// There was an error initializing the SSL session.
33- SslError ( SslError ) ,
210+ SslError ( Box < error :: Error + Sync + Send > ) ,
34211 /// There was an error communicating with the server.
35212 IoError ( io:: Error ) ,
36- /// The server sent an unexpected response.
37- BadResponse ,
38213}
39214
40215impl fmt:: Display for ConnectError {
@@ -60,14 +235,13 @@ impl error::Error for ConnectError {
60235 ConnectError :: NoSslSupport => "The server does not support SSL" ,
61236 ConnectError :: SslError ( _) => "Error initiating SSL session" ,
62237 ConnectError :: IoError ( _) => "Error communicating with server" ,
63- ConnectError :: BadResponse => "The server returned an unexpected response" ,
64238 }
65239 }
66240
67241 fn cause ( & self ) -> Option < & error:: Error > {
68242 match * self {
69243 ConnectError :: DbError ( ref err) => Some ( err) ,
70- ConnectError :: SslError ( ref err) => Some ( err) ,
244+ ConnectError :: SslError ( ref err) => Some ( & * * err) ,
71245 ConnectError :: IoError ( ref err) => Some ( err) ,
72246 _ => None
73247 }
@@ -86,12 +260,6 @@ impl From<DbError> for ConnectError {
86260 }
87261}
88262
89- impl From < SslError > for ConnectError {
90- fn from ( err : SslError ) -> ConnectError {
91- ConnectError :: SslError ( err)
92- }
93- }
94-
95263impl From < byteorder:: Error > for ConnectError {
96264 fn from ( err : byteorder:: Error ) -> ConnectError {
97265 ConnectError :: IoError ( From :: from ( err) )
@@ -119,18 +287,13 @@ pub enum Error {
119287 DbError ( DbError ) ,
120288 /// An error communicating with the Postgres server.
121289 IoError ( io:: Error ) ,
122- /// The communication channel with the Postgres server has desynchronized
123- /// due to an earlier communications error.
124- StreamDesynchronized ,
125290 /// An attempt was made to convert between incompatible Rust and Postgres
126291 /// types.
127292 WrongType ( Type ) ,
128293 /// An attempt was made to read from a column that does not exist.
129294 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 > ) ,
134297}
135298
136299impl fmt:: Display for Error {
@@ -148,20 +311,17 @@ impl error::Error for Error {
148311 match * self {
149312 Error :: DbError ( _) => "An error reported by the Postgres server" ,
150313 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- }
154314 Error :: WrongType ( _) => "Unexpected type" ,
155315 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" ,
158317 }
159318 }
160319
161320 fn cause ( & self ) -> Option < & error:: Error > {
162321 match * self {
163322 Error :: DbError ( ref err) => Some ( err) ,
164323 Error :: IoError ( ref err) => Some ( err) ,
324+ Error :: Conversion ( ref err) => Some ( & * * err) ,
165325 _ => None
166326 }
167327 }
0 commit comments