diff --git a/src/error.rs b/src/error.rs index 5e71e022..d627943b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,21 +17,73 @@ include!(concat!(env!("OUT_DIR"), "/sqlstate.rs")); /// A Postgres error or notice. #[derive(Clone, PartialEq, Eq, Debug)] pub struct DbError { - severity: String, - code: SqlState, - message: String, - detail: Option, - hint: Option, - position: Option, - where_: Option, - schema: Option, - table: Option, - column: Option, - datatype: Option, - constraint: Option, - file: String, - line: u32, - routine: String, + /// The field contents are ERROR, FATAL, or PANIC (in an error message), + /// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a + /// localized translation of one of these. + pub severity: String, + + /// The SQLSTATE code for the error. + pub code: SqlState, + + /// The primary human-readable error message. This should be accurate but + /// terse (typically one line). + pub message: String, + + /// An optional secondary error message carrying more detail about the + /// problem. Might run to multiple lines. + pub detail: Option, + + /// An optional suggestion what to do about the problem. This is intended + /// to differ from Detail in that it offers advice (potentially + /// inappropriate) rather than hard facts. Might run to multiple lines. + pub hint: Option, + + /// An optional error cursor position into either the original query string + /// or an internally generated query. + pub position: Option, + + /// An indication of the context in which the error occurred. Presently + /// this includes a call stack traceback of active procedural language + /// functions and internally-generated queries. The trace is one entry per + /// line, most recent first. + pub where_: Option, + + /// If the error was associated with a specific database object, the name + /// of the schema containing that object, if any. (PostgreSQL 9.3+) + pub schema: Option, + + /// If the error was associated with a specific table, the name of the + /// table. (Refer to the schema name field for the name of the table's + /// schema.) (PostgreSQL 9.3+) + pub table: Option, + + /// If the error was associated with a specific table column, the name of + /// the column. (Refer to the schema and table name fields to identify the + /// table.) (PostgreSQL 9.3+) + pub column: Option, + + /// If the error was associated with a specific data type, the name of the + /// data type. (Refer to the schema name field for the name of the data + /// type's schema.) (PostgreSQL 9.3+) + pub datatype: Option, + + /// If the error was associated with a specific constraint, the name of the + /// constraint. Refer to fields listed above for the associated table or + /// domain. (For this purpose, indexes are treated as constraints, even if + /// they weren't created with constraint syntax.) (PostgreSQL 9.3+) + pub constraint: Option, + + /// The file name of the source-code location where the error was reported. + pub file: String, + + /// The line number of the source-code location where the error was + /// reported. + pub line: u32, + + /// The name of the source-code routine reporting the error. + pub routine: String, + + _p: (), } impl DbErrorNew for DbError { @@ -66,6 +118,7 @@ impl DbErrorNew for DbError { file: try!(map.remove(&b'F').ok_or(())), line: try!(map.remove(&b'L').and_then(|l| l.parse().ok()).ok_or(())), routine: try!(map.remove(&b'R').ok_or(())), + _p: (), }) } @@ -84,104 +137,6 @@ impl DbErrorNew for DbError { } } -impl DbError { - /// The field contents are ERROR, FATAL, or PANIC (in an error message), - /// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a - /// localized translation of one of these. - pub fn severity(&self) -> &str { - &self.severity - } - - /// The SQLSTATE code for the error. - pub fn code(&self) -> &SqlState { - &self.code - } - - /// The primary human-readable error message. This should be accurate but - /// terse (typically one line). - pub fn message(&self) -> &str { - &self.message - } - - /// An optional secondary error message carrying more detail about the - /// problem. Might run to multiple lines. - pub fn detail(&self) -> Option<&str> { - self.detail.as_ref().map(|s| &**s) - } - - /// An optional suggestion what to do about the problem. This is intended - /// to differ from Detail in that it offers advice (potentially - /// inappropriate) rather than hard facts. Might run to multiple lines. - pub fn hint(&self) -> Option<&str> { - self.hint.as_ref().map(|s| &**s) - } - - /// An optional error cursor position into either the original query string - /// or an internally generated query. - pub fn position(&self) -> Option<&ErrorPosition> { - self.position.as_ref() - } - - /// An indication of the context in which the error occurred. Presently - /// this includes a call stack traceback of active procedural language - /// functions and internally-generated queries. The trace is one entry per - /// line, most recent first. - pub fn where_(&self) -> Option<&str> { - self.where_.as_ref().map(|s| &**s) - } - - /// If the error was associated with a specific database object, the name - /// of the schema containing that object, if any. (PostgreSQL 9.3+) - pub fn schema(&self) -> Option<&str> { - self.schema.as_ref().map(|s| &**s) - } - - /// If the error was associated with a specific table, the name of the - /// table. (Refer to the schema name field for the name of the table's - /// schema.) (PostgreSQL 9.3+) - pub fn table(&self) -> Option<&str> { - self.table.as_ref().map(|s| &**s) - } - - /// If the error was associated with a specific table column, the name of - /// the column. (Refer to the schema and table name fields to identify the - /// table.) (PostgreSQL 9.3+) - pub fn column(&self) -> Option<&str> { - self.column.as_ref().map(|s| &**s) - } - - /// If the error was associated with a specific data type, the name of the - /// data type. (Refer to the schema name field for the name of the data - /// type's schema.) (PostgreSQL 9.3+) - pub fn datatype(&self) -> Option<&str> { - self.datatype.as_ref().map(|s| &**s) - } - - /// If the error was associated with a specific constraint, the name of the - /// constraint. Refer to fields listed above for the associated table or - /// domain. (For this purpose, indexes are treated as constraints, even if - /// they weren't created with constraint syntax.) (PostgreSQL 9.3+) - pub fn constraint(&self) -> Option<&str> { - self.constraint.as_ref().map(|s| &**s) - } - - /// The file name of the source-code location where the error was reported. - pub fn file(&self) -> &str { - &self.file - } - - /// The line number of the source-code location where the error was - /// reported. - pub fn line(&self) -> u32 { - self.line - } - - /// The name of the source-code routine reporting the error. - pub fn routine(&self) -> &str { - &self.routine - } -} - impl fmt::Display for DbError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{}: {}", self.severity, self.message) diff --git a/src/lib.rs b/src/lib.rs index 238a3613..f777408f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -229,7 +229,7 @@ pub struct LoggingNoticeHandler; impl HandleNotice for LoggingNoticeHandler { fn handle_notice(&mut self, notice: DbError) { - info!("{}: {}", notice.severity(), notice.message()); + info!("{}: {}", notice.severity, notice.message); } } @@ -474,8 +474,8 @@ impl InnerConnection { WHERE t.oid = $1") { Ok(..) => return Ok(()), Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)), - // Range types weren't added until Postgres 9.2, so pg_range may not exist - Err(Error::DbError(ref e)) if e.code() == &SqlState::UndefinedTable => {} + // Range types weren't added until Postgres 9.2, so pg_range may not exist + Err(Error::DbError(ref e)) if e.code == SqlState::UndefinedTable => {} Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)), _ => unreachable!(), } diff --git a/tests/test.rs b/tests/test.rs index a4b5132d..889211d3 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -56,7 +56,7 @@ fn test_prepare_err() { let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None)); let stmt = conn.prepare("invalid sql database"); match stmt { - Err(Error::DbError(ref e)) if e.code() == &SyntaxError && e.position() == Some(&Normal(1)) => {} + Err(Error::DbError(ref e)) if e.code == SyntaxError && e.position == Some(Normal(1)) => {} Err(e) => panic!("Unexpected result {:?}", e), _ => panic!("Unexpected result"), } @@ -65,7 +65,7 @@ fn test_prepare_err() { #[test] fn test_unknown_database() { match Connection::connect("postgres://postgres@localhost/asdf", SslMode::None) { - Err(ConnectError::DbError(ref e)) if e.code() == &InvalidCatalogName => {} + Err(ConnectError::DbError(ref e)) if e.code == InvalidCatalogName => {} Err(resp) => panic!("Unexpected result {:?}", resp), _ => panic!("Unexpected result"), } @@ -339,7 +339,7 @@ fn test_batch_execute_error() { let stmt = conn.prepare("SELECT * FROM foo ORDER BY id"); match stmt { - Err(Error::DbError(ref e)) if e.code() == &UndefinedTable => {} + Err(Error::DbError(ref e)) if e.code == UndefinedTable => {} Err(e) => panic!("unexpected error {:?}", e), _ => panic!("unexpected success"), } @@ -382,7 +382,7 @@ FROM (SELECT gs.i ORDER BY gs.i LIMIT 2) ss")); match stmt.query(&[]) { - Err(Error::DbError(ref e)) if e.code() == &CardinalityViolation => {} + Err(Error::DbError(ref e)) if e.code == CardinalityViolation => {} Err(err) => panic!("Unexpected error {:?}", err), Ok(_) => panic!("Expected failure"), }; @@ -532,7 +532,7 @@ fn test_custom_notice_handler() { impl HandleNotice for Handler { fn handle_notice(&mut self, notice: DbError) { - assert_eq!("note", notice.message()); + assert_eq!("note", notice.message); unsafe { count += 1; } } } @@ -648,7 +648,7 @@ fn test_cancel_query() { }); match conn.execute("SELECT pg_sleep(10)", &[]) { - Err(Error::DbError(ref e)) if e.code() == &QueryCanceled => {} + Err(Error::DbError(ref e)) if e.code == QueryCanceled => {} Err(res) => panic!("Unexpected result {:?}", res), _ => panic!("Unexpected result"), } @@ -708,7 +708,7 @@ fn test_plaintext_pass_no_pass() { fn test_plaintext_pass_wrong_pass() { let ret = Connection::connect("postgres://pass_user:asdf@localhost/postgres", SslMode::None); match ret { - Err(ConnectError::DbError(ref e)) if e.code() == &InvalidPassword => {} + Err(ConnectError::DbError(ref e)) if e.code == InvalidPassword => {} Err(err) => panic!("Unexpected error {:?}", err), _ => panic!("Expected error") } @@ -733,7 +733,7 @@ fn test_md5_pass_no_pass() { fn test_md5_pass_wrong_pass() { let ret = Connection::connect("postgres://md5_user:asdf@localhost/postgres", SslMode::None); match ret { - Err(ConnectError::DbError(ref e)) if e.code() == &InvalidPassword => {} + Err(ConnectError::DbError(ref e)) if e.code == InvalidPassword => {} Err(err) => panic!("Unexpected error {:?}", err), _ => panic!("Expected error") } @@ -745,12 +745,12 @@ fn test_execute_copy_from_err() { or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[])); let stmt = or_panic!(conn.prepare("COPY foo (id) FROM STDIN")); match stmt.execute(&[]) { - Err(Error::DbError(ref err)) if err.message().contains("COPY") => {} + Err(Error::DbError(ref err)) if err.message.contains("COPY") => {} Err(err) => panic!("Unexpected error {:?}", err), _ => panic!("Expected error"), } match stmt.query(&[]) { - Err(Error::DbError(ref err)) if err.message().contains("COPY") => {} + Err(Error::DbError(ref err)) if err.message.contains("COPY") => {} Err(err) => panic!("Unexpected error {:?}", err), _ => panic!("Expected error"), }; @@ -761,7 +761,7 @@ fn test_batch_execute_copy_from_err() { let conn = or_panic!(Connection::connect("postgres://postgres@localhost", SslMode::None)); or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[])); match conn.batch_execute("COPY foo (id) FROM STDIN") { - Err(Error::DbError(ref err)) if err.message().contains("COPY") => {} + Err(Error::DbError(ref err)) if err.message.contains("COPY") => {} Err(err) => panic!("Unexpected error {:?}", err), _ => panic!("Expected error"), }