Parsing of ErrorResponse and NoticeResponse
PostgresDbError::new plays a little fast and loose with the expected format. Hopefully that's okay. Closes #4
This commit is contained in:
78
src/lib.rs
78
src/lib.rs
@@ -39,10 +39,8 @@ macro_rules! match_read_message(
|
||||
)
|
||||
|
||||
fn handle_notice_response(fields: ~[(u8, ~str)]) {
|
||||
// move_rev_iter is more efficient than move_iter
|
||||
let map: HashMap<u8, ~str> = fields.move_rev_iter().collect();
|
||||
info!("%s: %s", map.find(&('S' as u8)).unwrap().as_slice(),
|
||||
map.find(&('M' as u8)).unwrap().as_slice());
|
||||
let err = PostgresDbError::new(fields);
|
||||
info!("%s: %s", err.severity, err.message);
|
||||
}
|
||||
|
||||
pub struct PostgresConnection {
|
||||
@@ -68,8 +66,53 @@ pub enum PostgresConnectError {
|
||||
}
|
||||
|
||||
#[deriving(ToStr)]
|
||||
// TODO this should have things in it
|
||||
pub struct PostgresDbError;
|
||||
pub enum PostgresErrorPosition {
|
||||
Position(uint),
|
||||
InternalPosition {
|
||||
position: uint,
|
||||
query: ~str
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(ToStr)]
|
||||
pub struct PostgresDbError {
|
||||
// This could almost be an enum, except the values can be localized :(
|
||||
severity: ~str,
|
||||
// Should probably end up as an enum
|
||||
code: ~str,
|
||||
message: ~str,
|
||||
position: Option<PostgresErrorPosition>,
|
||||
where: Option<~str>,
|
||||
file: ~str,
|
||||
line: uint,
|
||||
routine: ~str
|
||||
}
|
||||
|
||||
impl PostgresDbError {
|
||||
fn new(fields: ~[(u8, ~str)]) -> PostgresDbError {
|
||||
// move_rev_iter is more efficient than move_iter
|
||||
let mut map: HashMap<u8, ~str> = fields.move_rev_iter().collect();
|
||||
PostgresDbError {
|
||||
severity: map.pop(&('S' as u8)).unwrap(),
|
||||
code: map.pop(&('C' as u8)).unwrap(),
|
||||
message: map.pop(&('M' as u8)).unwrap(),
|
||||
position: match map.pop(&('P' as u8)) {
|
||||
Some(pos) => Some(Position(FromStr::from_str(pos).unwrap())),
|
||||
None => match map.pop(&('p' as u8)) {
|
||||
Some(pos) => Some(InternalPosition {
|
||||
position: FromStr::from_str(pos).unwrap(),
|
||||
query: map.pop(&('q' as u8)).unwrap()
|
||||
}),
|
||||
None => None
|
||||
}
|
||||
},
|
||||
where: map.pop(&('W' as u8)),
|
||||
file: map.pop(&('F' as u8)).unwrap(),
|
||||
line: FromStr::from_str(map.pop(&('L' as u8)).unwrap()).unwrap(),
|
||||
routine: map.pop(&('R' as u8)).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PostgresConnection {
|
||||
pub fn connect(url: &str) -> PostgresConnection {
|
||||
@@ -131,8 +174,8 @@ impl PostgresConnection {
|
||||
match_read_message!(conn, {
|
||||
ParameterStatus { parameter, value } =>
|
||||
info!("Parameter %s = %s", parameter, value),
|
||||
BackendKeyData { _ } => (),
|
||||
ReadyForQuery { _ } => break,
|
||||
BackendKeyData {_} => (),
|
||||
ReadyForQuery {_} => break,
|
||||
resp => fail!("Bad response: %?", resp.to_str())
|
||||
})
|
||||
}
|
||||
@@ -185,7 +228,8 @@ impl PostgresConnection {
|
||||
|
||||
match_read_message!(self, {
|
||||
AuthenticationOk => None,
|
||||
ErrorResponse {_} => Some(DbError(PostgresDbError)),
|
||||
ErrorResponse { fields } =>
|
||||
Some(DbError(PostgresDbError::new(fields))),
|
||||
resp => fail!("Bad response: %?", resp.to_str())
|
||||
})
|
||||
}
|
||||
@@ -214,7 +258,8 @@ impl PostgresConnection {
|
||||
|
||||
match self.read_message() {
|
||||
ParseComplete => (),
|
||||
ErrorResponse {_} => return Err(PostgresDbError),
|
||||
ErrorResponse { fields } =>
|
||||
return Err(PostgresDbError::new(fields)),
|
||||
resp => fail!("Bad response: %?", resp.to_str())
|
||||
}
|
||||
|
||||
@@ -269,7 +314,8 @@ impl PostgresConnection {
|
||||
loop {
|
||||
match_read_message!(self, {
|
||||
ReadyForQuery {_} => break,
|
||||
resp @ ErrorResponse {_} => fail!("Error: %?", resp.to_str()),
|
||||
ErrorResponse { fields } =>
|
||||
fail!("Error: %s", PostgresDbError::new(fields).to_str()),
|
||||
_ => ()
|
||||
})
|
||||
}
|
||||
@@ -375,7 +421,7 @@ impl<'self> PostgresStatement<'self> {
|
||||
|
||||
match_read_message!(self.conn, {
|
||||
BindComplete => None,
|
||||
ErrorResponse {_} => Some(PostgresDbError),
|
||||
ErrorResponse { fields } => Some(PostgresDbError::new(fields)),
|
||||
resp => fail!("Bad response: %?", resp.to_str())
|
||||
})
|
||||
}
|
||||
@@ -412,9 +458,9 @@ impl<'self> PostgresStatement<'self> {
|
||||
DataRow {_} => (),
|
||||
EmptyQueryResponse => break,
|
||||
NoticeResponse {_} => (),
|
||||
ErrorResponse {_} => {
|
||||
ErrorResponse { fields } => {
|
||||
self.conn.wait_for_ready();
|
||||
return Err(PostgresDbError);
|
||||
return Err(PostgresDbError::new(fields));
|
||||
},
|
||||
resp => fail!("Bad response: %?", resp.to_str())
|
||||
})
|
||||
@@ -452,9 +498,9 @@ impl<'self> PostgresStatement<'self> {
|
||||
DataRow { row } => data.push(row),
|
||||
CommandComplete {_} => break,
|
||||
NoticeResponse {_} => (),
|
||||
ErrorResponse {_} => {
|
||||
ErrorResponse { fields } => {
|
||||
self.conn.wait_for_ready();
|
||||
return Err(PostgresDbError);
|
||||
return Err(PostgresDbError::new(fields));
|
||||
},
|
||||
resp => fail!("Bad response: %?", resp.to_str())
|
||||
})
|
||||
|
||||
41
src/test.rs
41
src/test.rs
@@ -1,6 +1,6 @@
|
||||
extern mod postgres;
|
||||
|
||||
use postgres::{PostgresConnection};
|
||||
use postgres::*;
|
||||
use postgres::types::ToSql;
|
||||
|
||||
#[test]
|
||||
@@ -17,7 +17,16 @@ fn test_basic() {
|
||||
#[test]
|
||||
fn test_prepare_err() {
|
||||
let conn = PostgresConnection::connect("postgres://postgres@127.0.0.1:5432");
|
||||
assert!(conn.try_prepare("invalid sql statment").is_err());
|
||||
match conn.try_prepare("invalid sql statment") {
|
||||
Err(PostgresDbError { position, code, _ }) => {
|
||||
assert_eq!(code, ~"42601");
|
||||
match position {
|
||||
Some(Position(1)) => (),
|
||||
position => fail!("Unexpected position %?", position)
|
||||
}
|
||||
}
|
||||
resp => fail!("Unexpected result %?", resp)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -65,15 +74,21 @@ fn test_plaintext_pass() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_plaintext_pass_no_pass() {
|
||||
PostgresConnection::connect("postgres://pass_user@127.0.0.1:5432");
|
||||
let ret = PostgresConnection::try_connect("postgres://pass_user@127.0.0.1:5432");
|
||||
match ret {
|
||||
Err(MissingPassword) => (),
|
||||
ret => fail!("Unexpected result %?", ret)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_plaintext_pass_wrong_pass() {
|
||||
PostgresConnection::connect("postgres://pass_user:asdf@127.0.0.1:5432");
|
||||
let ret = PostgresConnection::try_connect("postgres://pass_user:asdf@127.0.0.1:5432");
|
||||
match ret {
|
||||
Err(DbError(PostgresDbError { code, _ })) => assert_eq!(code, ~"28P01"),
|
||||
ret => fail!("Unexpected result %?", ret)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -82,13 +97,19 @@ fn test_md5_pass() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_md5_pass_no_pass() {
|
||||
PostgresConnection::connect("postgres://md5_user@127.0.0.1:5432");
|
||||
let ret = PostgresConnection::try_connect("postgres://md5_user@127.0.0.1:5432");
|
||||
match ret {
|
||||
Err(MissingPassword) => (),
|
||||
ret => fail!("Unexpected result %?", ret)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_md5_pass_wrong_pass() {
|
||||
PostgresConnection::connect("postgres://md5_user:asdf@127.0.0.1:5432");
|
||||
let ret = PostgresConnection::try_connect("postgres://md5_user:asdf@127.0.0.1:5432");
|
||||
match ret {
|
||||
Err(DbError(PostgresDbError { code, _ })) => assert_eq!(code, ~"28P01"),
|
||||
ret => fail!("Unexpected result %?", ret)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user