Skip to content

Commit 6afc2ca

Browse files
committed
Fix error handling for prepare, result and query
Closes #2
1 parent 594830b commit 6afc2ca

File tree

2 files changed

+76
-22
lines changed

2 files changed

+76
-22
lines changed

src/lib.rs

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,19 @@ impl Drop for PostgresConnection {
2626
}
2727
}
2828

29-
#[deriving(ToStr)]
30-
pub struct PostgresError;
31-
3229
#[deriving(ToStr)]
3330
pub enum PostgresConnectError {
3431
InvalidUrl,
3532
MissingUser,
36-
DbError(PostgresError),
33+
DbError(PostgresDbError),
3734
MissingPassword,
3835
UnsupportedAuthentication
3936
}
4037

38+
#[deriving(ToStr)]
39+
// TODO this should have things in it
40+
pub struct PostgresDbError;
41+
4142
impl PostgresConnection {
4243
pub fn connect(url: &str) -> PostgresConnection {
4344
match PostgresConnection::try_connect(url) {
@@ -65,7 +66,9 @@ impl PostgresConnection {
6566
};
6667
let mut args = args;
6768

68-
let socket_url = fmt!("%s:%s", host, port.unwrap_or_default(~"5432"));
69+
// This seems silly
70+
let socket_url = format!("{:s}:{:s}", host,
71+
port.unwrap_or_default(~"5432"));
6972
let addr: SocketAddr = match FromStr::from_str(socket_url) {
7073
Some(addr) => addr,
7174
None => return Err(InvalidUrl)
@@ -77,7 +80,7 @@ impl PostgresConnection {
7780
next_stmt_id: Cell::new(0)
7881
};
7982
80-
// we have to clone here since we need the user again for auth
83+
// We have to clone here since we need the user again for auth
8184
args.push((~"user", user.user.clone()));
8285
if !path.is_empty() {
8386
args.push((~"database", path));
@@ -124,7 +127,7 @@ impl PostgresConnection {
124127
};
125128
self.write_message(&PasswordMessage(pass));
126129
}
127-
AuthenticationMD5Password(nonce) => {
130+
AuthenticationMD5Password(salt) => {
128131
let UserInfo { user, pass } = user;
129132
let pass = match pass {
130133
Some(pass) => pass,
@@ -136,7 +139,7 @@ impl PostgresConnection {
136139
let output = md5.result_str();
137140
md5.reset();
138141
md5.input_str(output);
139-
md5.input(nonce);
142+
md5.input(salt);
140143
let output = "md5" + md5.result_str();
141144
self.write_message(&PasswordMessage(output.as_slice()));
142145
}
@@ -145,12 +148,21 @@ impl PostgresConnection {
145148
146149
match self.read_message() {
147150
AuthenticationOk => None,
148-
ErrorResponse(*) => Some(DbError(PostgresError)),
151+
ErrorResponse(*) => Some(DbError(PostgresDbError)),
149152
resp => fail!("Bad response: %?", resp.to_str())
150153
}
151154
}
152155
153156
pub fn prepare<'a>(&'a self, query: &str) -> PostgresStatement<'a> {
157+
match self.try_prepare(query) {
158+
Ok(stmt) => stmt,
159+
Err(err) => fail!("Error preparing \"%s\": %s", query,
160+
err.to_str())
161+
}
162+
}
163+
164+
pub fn try_prepare<'a>(&'a self, query: &str)
165+
-> Result<PostgresStatement<'a>, PostgresDbError> {
154166
let id = self.next_stmt_id.take();
155167
let stmt_name = format!("statement_{}", id);
156168
self.next_stmt_id.put_back(id + 1);
@@ -161,7 +173,7 @@ impl PostgresConnection {
161173
162174
match self.read_message() {
163175
ParseComplete => (),
164-
resp @ ErrorResponse(*) => fail!("Error: %?", resp.to_str()),
176+
ErrorResponse(*) => return Err(PostgresDbError),
165177
resp => fail!("Bad response: %?", resp.to_str())
166178
}
167179
@@ -182,12 +194,12 @@ impl PostgresConnection {
182194
183195
self.wait_for_ready();
184196
185-
PostgresStatement {
197+
Ok(PostgresStatement {
186198
conn: self,
187199
name: stmt_name,
188200
num_params: num_params,
189201
next_portal_id: Cell::new(0)
190-
}
202+
})
191203
}
192204
193205
pub fn in_transaction<T, E: ToStr>(&self, blk: &fn(&PostgresConnection)
@@ -257,7 +269,8 @@ impl<'self> PostgresStatement<'self> {
257269
self.num_params
258270
}
259271
260-
fn execute(&self, portal_name: &str, params: &[&ToSql]) {
272+
fn execute(&self, portal_name: &str, params: &[&ToSql])
273+
-> Option<PostgresDbError> {
261274
if self.num_params != params.len() {
262275
fail!("Expected %u params but got %u", self.num_params,
263276
params.len());
@@ -274,15 +287,29 @@ impl<'self> PostgresStatement<'self> {
274287
self.conn.write_message(&Sync);
275288
276289
match self.conn.read_message() {
277-
BindComplete => (),
278-
resp @ ErrorResponse(*) => fail!("Error: %?", resp.to_str()),
290+
BindComplete => None,
291+
ErrorResponse(*) => Some(PostgresDbError),
279292
resp => fail!("Bad response: %?", resp.to_str())
280293
}
281294
}
282295
283296
pub fn update(&self, params: &[&ToSql]) -> uint {
297+
match self.try_update(params) {
298+
Ok(count) => count,
299+
Err(err) => fail!("Error running update: %s", err.to_str())
300+
}
301+
}
302+
303+
pub fn try_update(&self, params: &[&ToSql])
304+
-> Result<uint, PostgresDbError> {
284305
// The unnamed portal is automatically cleaned up at sync time
285-
self.execute("", params);
306+
match self.execute("", params) {
307+
Some(err) => {
308+
self.conn.wait_for_ready();
309+
return Err(err);
310+
}
311+
None => ()
312+
}
286313
287314
let mut num = 0;
288315
loop {
@@ -298,21 +325,38 @@ impl<'self> PostgresStatement<'self> {
298325
DataRow(*) => (),
299326
EmptyQueryResponse => break,
300327
NoticeResponse(*) => (),
301-
resp @ ErrorResponse(*) => fail!("Error: %?", resp.to_str()),
328+
ErrorResponse(*) => {
329+
self.conn.wait_for_ready();
330+
return Err(PostgresDbError);
331+
}
302332
resp => fail!("Bad response: %?", resp.to_str())
303333
}
304334
}
305335
self.conn.wait_for_ready();
306336
307-
num
337+
Ok(num)
308338
}
309339
310340
pub fn query<'a>(&'a self, params: &[&ToSql]) -> PostgresResult<'a> {
341+
match self.try_query(params) {
342+
Ok(result) => result,
343+
Err(err) => fail!("Error running query: %s", err.to_str())
344+
}
345+
}
346+
347+
pub fn try_query<'a>(&'a self, params: &[&ToSql])
348+
-> Result<PostgresResult<'a>, PostgresDbError> {
311349
let id = self.next_portal_id.take();
312350
let portal_name = format!("{:s}_portal_{}", self.name.as_slice(), id);
313351
self.next_portal_id.put_back(id + 1);
314352
315-
self.execute(portal_name, params);
353+
match self.execute(portal_name, params) {
354+
Some(err) => {
355+
self.conn.wait_for_ready();
356+
return Err(err);
357+
}
358+
None => ()
359+
}
316360
317361
let mut data = ~[];
318362
loop {
@@ -321,16 +365,20 @@ impl<'self> PostgresStatement<'self> {
321365
DataRow(row) => data.push(row),
322366
CommandComplete(*) => break,
323367
NoticeResponse(*) => (),
324-
resp @ ErrorResponse(*) => fail!("Error: %?", resp.to_str()),
368+
ErrorResponse(*) => {
369+
self.conn.wait_for_ready();
370+
return Err(PostgresDbError);
371+
}
325372
resp => fail!("Bad response: %?", resp.to_str())
326373
}
327374
}
375+
self.conn.wait_for_ready();
328376

329-
PostgresResult {
377+
Ok(PostgresResult {
330378
stmt: self,
331379
name: portal_name,
332380
data: data
333-
}
381+
})
334382
}
335383
}
336384

src/test.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ fn test_basic() {
1313
};
1414
}
1515

16+
#[test]
17+
fn test_prepare_err() {
18+
let conn = PostgresConnection::connect("postgres://postgres@127.0.0.1:5432");
19+
assert!(conn.try_prepare("invalid sql statment").is_err());
20+
}
21+
1622
#[test]
1723
fn test_query() {
1824
let conn = PostgresConnection::connect("postgres://postgres@127.0.0.1:5432");

0 commit comments

Comments
 (0)