Skip to content

Commit 7cfde75

Browse files
committed
Encapsulate DbError
1 parent 219ce2a commit 7cfde75

3 files changed

Lines changed: 128 additions & 68 deletions

File tree

src/error.rs

Lines changed: 112 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -466,60 +466,24 @@ pub enum ErrorPosition {
466466
}
467467
}
468468

469-
/// Encapsulates a Postgres error or notice.
469+
/// A Postgres error or notice.
470470
#[derive(Clone, PartialEq, Eq, Debug)]
471471
pub struct DbError {
472-
/// The field contents are ERROR, FATAL, or PANIC (in an error message),
473-
/// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
474-
/// localized translation of one of these.
475-
pub severity: String,
476-
/// The SQLSTATE code for the error.
477-
pub code: SqlState,
478-
/// The primary human-readable error message. This should be accurate but
479-
/// terse (typically one line).
480-
pub message: String,
481-
/// An optional secondary error message carrying more detail about the
482-
/// problem. Might run to multiple lines.
483-
pub detail: Option<String>,
484-
/// An optional suggestion what to do about the problem. This is intended
485-
/// to differ from Detail in that it offers advice (potentially
486-
/// inappropriate) rather than hard facts. Might run to multiple lines.
487-
pub hint: Option<String>,
488-
/// An optional error cursor position into either the original query string
489-
/// or an internally generated query.
490-
pub position: Option<ErrorPosition>,
491-
/// An indication of the context in which the error occurred. Presently
492-
/// this includes a call stack traceback of active procedural language
493-
/// functions and internally-generated queries. The trace is one entry per
494-
/// line, most recent first.
495-
pub where_: Option<String>,
496-
/// If the error was associated with a specific database object, the name
497-
/// of the schema containing that object, if any. (PostgreSQL 9.3+)
498-
pub schema: Option<String>,
499-
/// If the error was associated with a specific table, the name of the
500-
/// table. (Refer to the schema name field for the name of the table's
501-
/// schema.) (PostgreSQL 9.3+)
502-
pub table: Option<String>,
503-
/// If the error was associated with a specific table column, the name of
504-
/// the column. (Refer to the schema and table name fields to identify the
505-
/// table.) (PostgreSQL 9.3+)
506-
pub column: Option<String>,
507-
/// If the error was associated with a specific data type, the name of the
508-
/// data type. (Refer to the schema name field for the name of the data
509-
/// type's schema.) (PostgreSQL 9.3+)
510-
pub datatype: Option<String>,
511-
/// If the error was associated with a specific constraint, the name of the
512-
/// constraint. Refer to fields listed above for the associated table or
513-
/// domain. (For this purpose, indexes are treated as constraints, even if
514-
/// they weren't created with constraint syntax.) (PostgreSQL 9.3+)
515-
pub constraint: Option<String>,
516-
/// The file name of the source-code location where the error was reported.
517-
pub file: String,
518-
/// The line number of the source-code location where the error was
519-
/// reported.
520-
pub line: usize,
521-
/// The name of the source-code routine reporting the error.
522-
pub routine: String
472+
severity: String,
473+
code: SqlState,
474+
message: String,
475+
detail: Option<String>,
476+
hint: Option<String>,
477+
position: Option<ErrorPosition>,
478+
where_: Option<String>,
479+
schema: Option<String>,
480+
table: Option<String>,
481+
column: Option<String>,
482+
datatype: Option<String>,
483+
constraint: Option<String>,
484+
file: String,
485+
line: u32,
486+
routine: String
523487
}
524488

525489
impl DbError {
@@ -569,6 +533,102 @@ impl DbError {
569533
Err(()) => Err(Error::BadData),
570534
}
571535
}
536+
537+
/// The field contents are ERROR, FATAL, or PANIC (in an error message),
538+
/// or WARNING, NOTICE, DEBUG, INFO, or LOG (in a notice message), or a
539+
/// localized translation of one of these.
540+
pub fn severity(&self) -> &str {
541+
&self.severity
542+
}
543+
544+
/// The SQLSTATE code for the error.
545+
pub fn code(&self) -> &SqlState {
546+
&self.code
547+
}
548+
549+
/// The primary human-readable error message. This should be accurate but
550+
/// terse (typically one line).
551+
pub fn message(&self) -> &str {
552+
&self.message
553+
}
554+
555+
/// An optional secondary error message carrying more detail about the
556+
/// problem. Might run to multiple lines.
557+
pub fn detail(&self) -> Option<&str> {
558+
self.detail.as_ref().map(|s| &**s)
559+
}
560+
561+
/// An optional suggestion what to do about the problem. This is intended
562+
/// to differ from Detail in that it offers advice (potentially
563+
/// inappropriate) rather than hard facts. Might run to multiple lines.
564+
pub fn hint(&self) -> Option<&str> {
565+
self.hint.as_ref().map(|s| &**s)
566+
}
567+
568+
/// An optional error cursor position into either the original query string
569+
/// or an internally generated query.
570+
pub fn position(&self) -> Option<&ErrorPosition> {
571+
self.position.as_ref()
572+
}
573+
574+
/// An indication of the context in which the error occurred. Presently
575+
/// this includes a call stack traceback of active procedural language
576+
/// functions and internally-generated queries. The trace is one entry per
577+
/// line, most recent first.
578+
pub fn where_(&self) -> Option<&str> {
579+
self.where_.as_ref().map(|s| &**s)
580+
}
581+
582+
/// If the error was associated with a specific database object, the name
583+
/// of the schema containing that object, if any. (PostgreSQL 9.3+)
584+
pub fn schema(&self) -> Option<&str> {
585+
self.schema.as_ref().map(|s| &**s)
586+
}
587+
588+
/// If the error was associated with a specific table, the name of the
589+
/// table. (Refer to the schema name field for the name of the table's
590+
/// schema.) (PostgreSQL 9.3+)
591+
pub fn table(&self) -> Option<&str> {
592+
self.table.as_ref().map(|s| &**s)
593+
}
594+
595+
/// If the error was associated with a specific table column, the name of
596+
/// the column. (Refer to the schema and table name fields to identify the
597+
/// table.) (PostgreSQL 9.3+)
598+
pub fn column(&self) -> Option<&str> {
599+
self.column.as_ref().map(|s| &**s)
600+
}
601+
602+
/// If the error was associated with a specific data type, the name of the
603+
/// data type. (Refer to the schema name field for the name of the data
604+
/// type's schema.) (PostgreSQL 9.3+)
605+
pub fn datatype(&self) -> Option<&str> {
606+
self.datatype.as_ref().map(|s| &**s)
607+
}
608+
609+
/// If the error was associated with a specific constraint, the name of the
610+
/// constraint. Refer to fields listed above for the associated table or
611+
/// domain. (For this purpose, indexes are treated as constraints, even if
612+
/// they weren't created with constraint syntax.) (PostgreSQL 9.3+)
613+
pub fn constraint(&self) -> Option<&str> {
614+
self.constraint.as_ref().map(|s| &**s)
615+
}
616+
617+
/// The file name of the source-code location where the error was reported.
618+
pub fn file(&self) -> &str {
619+
&self.file
620+
}
621+
622+
/// The line number of the source-code location where the error was
623+
/// reported.
624+
pub fn line(&self) -> u32 {
625+
self.line
626+
}
627+
628+
/// The name of the source-code routine reporting the error.
629+
pub fn routine(&self) -> &str {
630+
&self.routine
631+
}
572632
}
573633

574634
impl fmt::Display for DbError {

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ pub struct DefaultNoticeHandler;
211211

212212
impl NoticeHandler for DefaultNoticeHandler {
213213
fn handle(&mut self, notice: DbError) {
214-
info!("{}: {}", notice.severity, notice.message);
214+
info!("{}: {}", notice.severity(), notice.message());
215215
}
216216
}
217217

@@ -477,7 +477,7 @@ impl InnerConnection {
477477
Ok(..) => return Ok(()),
478478
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
479479
// Range types weren't added until Postgres 9.2, so pg_range may not exist
480-
Err(Error::DbError(DbError { code: SqlState::UndefinedTable, .. })) => {}
480+
Err(Error::DbError(ref e)) if e.code() == &SqlState::UndefinedTable => {}
481481
Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)),
482482
_ => unreachable!()
483483
}

tests/test.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn test_url_terminating_slash() {
5656
fn test_prepare_err() {
5757
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
5858
match conn.prepare("invalid sql statment") {
59-
Err(Error::DbError(DbError { code: SyntaxError, 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(DbError { code: InvalidCatalogName, .. })) => {}
68+
Err(ConnectError::DbError(ref e)) if e.code() == &InvalidCatalogName => {}
6969
Err(resp) => panic!("Unexpected result {:?}", resp),
7070
_ => panic!("Unexpected result"),
7171
}
@@ -336,7 +336,7 @@ fn test_batch_execute_error() {
336336
conn.batch_execute(query).err().unwrap();
337337

338338
match conn.prepare("SELECT * from foo ORDER BY id") {
339-
Err(Error::DbError(DbError { code: UndefinedTable, .. })) => {},
339+
Err(Error::DbError(ref e)) if e.code() == &UndefinedTable => {}
340340
Err(e) => panic!("unexpected error {:?}", e),
341341
_ => panic!("unexpected success"),
342342
}
@@ -379,7 +379,7 @@ FROM (SELECT gs.i
379379
ORDER BY gs.i
380380
LIMIT 2) ss"));
381381
match stmt.query(&[]) {
382-
Err(Error::DbError(DbError { code: CardinalityViolation, .. })) => {}
382+
Err(Error::DbError(ref e)) if e.code() == &CardinalityViolation => {}
383383
Err(err) => panic!("Unexpected error {:?}", err),
384384
Ok(_) => panic!("Expected failure"),
385385
}
@@ -526,7 +526,7 @@ fn test_custom_notice_handler() {
526526

527527
impl NoticeHandler for Handler {
528528
fn handle(&mut self, notice: DbError) {
529-
assert_eq!("note", &*notice.message);
529+
assert_eq!("note", notice.message());
530530
unsafe { count += 1; }
531531
}
532532
}
@@ -657,7 +657,7 @@ fn test_cancel_query() {
657657
});
658658

659659
match conn.execute("SELECT pg_sleep(10)", &[]) {
660-
Err(Error::DbError(DbError { code: QueryCanceled, .. })) => {}
660+
Err(Error::DbError(ref e)) if e.code() == &QueryCanceled => {}
661661
Err(res) => panic!("Unexpected result {:?}", res),
662662
_ => panic!("Unexpected result"),
663663
}
@@ -698,7 +698,7 @@ fn test_plaintext_pass_no_pass() {
698698
fn test_plaintext_pass_wrong_pass() {
699699
let ret = Connection::connect("postgres://pass_user:asdf@localhost/postgres", &SslMode::None);
700700
match ret {
701-
Err(ConnectError::DbError(DbError { code: InvalidPassword, .. })) => (),
701+
Err(ConnectError::DbError(ref e)) if e.code() == &InvalidPassword => {}
702702
Err(err) => panic!("Unexpected error {:?}", err),
703703
_ => panic!("Expected error")
704704
}
@@ -723,7 +723,7 @@ fn test_md5_pass_no_pass() {
723723
fn test_md5_pass_wrong_pass() {
724724
let ret = Connection::connect("postgres://md5_user:asdf@localhost/postgres", &SslMode::None);
725725
match ret {
726-
Err(ConnectError::DbError(DbError { code: InvalidPassword, .. })) => (),
726+
Err(ConnectError::DbError(ref e)) if e.code() == &InvalidPassword => {}
727727
Err(err) => panic!("Unexpected error {:?}", err),
728728
_ => panic!("Expected error")
729729
}
@@ -735,12 +735,12 @@ fn test_execute_copy_from_err() {
735735
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]));
736736
let stmt = or_panic!(conn.prepare("COPY foo (id) FROM STDIN"));
737737
match stmt.execute(&[]) {
738-
Err(Error::DbError(ref err)) if err.message[].contains("COPY") => {}
738+
Err(Error::DbError(ref err)) if err.message().contains("COPY") => {}
739739
Err(err) => panic!("Unexptected error {:?}", err),
740740
_ => panic!("Expected error"),
741741
}
742742
match stmt.query(&[]) {
743-
Err(Error::DbError(ref err)) if err.message[].contains("COPY") => {}
743+
Err(Error::DbError(ref err)) if err.message().contains("COPY") => {}
744744
Err(err) => panic!("Unexptected error {:?}", err),
745745
_ => panic!("Expected error"),
746746
}
@@ -779,7 +779,7 @@ fn test_copy_in_bad_column_count() {
779779

780780
let res = stmt.execute(data);
781781
match res {
782-
Err(Error::DbError(ref err)) if err.message[].contains("Invalid column count") => {}
782+
Err(Error::DbError(ref err)) if err.message().contains("Invalid column count") => {}
783783
Err(err) => panic!("unexpected error {:?}", err),
784784
_ => panic!("Expected error"),
785785
}
@@ -794,7 +794,7 @@ fn test_copy_in_bad_column_count() {
794794

795795
let res = stmt.execute(data);
796796
match res {
797-
Err(Error::DbError(ref err)) if err.message[].contains("Invalid column count") => {}
797+
Err(Error::DbError(ref err)) if err.message().contains("Invalid column count") => {}
798798
Err(err) => panic!("unexpected error {:?}", err),
799799
_ => panic!("Expected error"),
800800
}
@@ -818,7 +818,7 @@ fn test_copy_in_bad_type() {
818818

819819
let res = stmt.execute(data);
820820
match res {
821-
Err(Error::DbError(ref err)) if err.message[].contains("saw type Varchar") => {}
821+
Err(Error::DbError(ref err)) if err.message().contains("saw type Varchar") => {}
822822
Err(err) => panic!("unexpected error {:?}", err),
823823
_ => panic!("Expected error"),
824824
}
@@ -831,7 +831,7 @@ fn test_batch_execute_copy_from_err() {
831831
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
832832
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]));
833833
match conn.batch_execute("COPY foo (id) FROM STDIN") {
834-
Err(Error::DbError(ref err)) if err.message[].contains("COPY") => {}
834+
Err(Error::DbError(ref err)) if err.message().contains("COPY") => {}
835835
Err(err) => panic!("Unexptected error {:?}", err),
836836
_ => panic!("Expected error"),
837837
}

0 commit comments

Comments
 (0)