From 2b617e61b1fdb0164daf4b74e065a6c8d9756ac0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 22 Aug 2013 03:12:35 -0400 Subject: [PATCH] Beginnings of Bind support --- src/lib.rs | 46 ++++++++++++++++++++++++++++++++++------- src/message.rs | 55 +++++++++++++++++++++++++++++++++++++++++++------- src/test.rs | 1 + 3 files changed, 88 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1d65fdfb..791850d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,11 +18,7 @@ pub struct PostgresConnection { impl Drop for PostgresConnection { fn drop(&self) { - do io_error::cond.trap(|_| { }).inside { - do self.stream.with_mut_ref |s| { - s.write_message(&Terminate); - } - } + self.write_message(&Terminate); } } @@ -111,7 +107,8 @@ impl PostgresConnection { PostgresStatement { conn: self, name: stmt_name, - num_params: num_params + num_params: num_params, + next_portal_id: Cell::new(0) } } @@ -126,9 +123,44 @@ impl PostgresConnection { pub struct PostgresStatement<'self> { priv conn: &'self PostgresConnection, priv name: ~str, - priv num_params: uint + priv num_params: uint, + priv next_portal_id: Cell +} + +#[unsafe_destructor] +impl<'self> Drop for PostgresStatement<'self> { + fn drop(&self) { + self.conn.write_message(&Close('S' as u8, self.name.as_slice())); + self.conn.write_message(&Sync); + self.conn.read_message(); // CloseComplete or ErrorResponse + self.conn.wait_for_ready(); + } } impl<'self> PostgresStatement<'self> { + pub fn num_params(&self) -> uint { + self.num_params + } + pub fn query(&self) { + let id = self.next_portal_id.take(); + let portal_name = ifmt!("{:s}_portal_{}", self.name.as_slice(), id); + self.next_portal_id.put_back(id + 1); + + let formats = []; + let values = []; + let result_formats = []; + + self.conn.write_message(&Bind(portal_name, self.name.as_slice(), + formats, values, result_formats)); + self.conn.write_message(&Sync); + + match self.conn.read_message() { + BindComplete => (), + ErrorResponse(ref data) => fail!("Error: %?", data), + resp => fail!("Bad response: %?", resp) + } + + self.conn.wait_for_ready(); + } } diff --git a/src/message.rs b/src/message.rs index 32f8f060..a2bb33ee 100644 --- a/src/message.rs +++ b/src/message.rs @@ -12,6 +12,8 @@ pub static PROTOCOL_VERSION: i32 = 0x0003_0000; pub enum BackendMessage { AuthenticationOk, BackendKeyData(i32, i32), + BindComplete, + CloseComplete, ErrorResponse(HashMap), NoData, ParameterDescription(~[i32]), @@ -32,6 +34,10 @@ pub struct RowDescriptionEntry { } pub enum FrontendMessage<'self> { + /// portal, stmt, formats, values, result formats + Bind(&'self str, &'self str, &'self [i16], &'self [Option<&'self [u8]>], + &'self [i16]), + Close(u8, &'self str), Describe(u8, &'self str), /// name, query, parameter types Parse(&'self str, &'self str, &'self [i32]), @@ -63,23 +69,56 @@ impl WriteMessage for W { let mut ident = None; match *message { - Describe(variant, ref name) => { + Bind(portal, stmt, formats, values, result_formats) => { + ident = Some('B'); + buf.write_string(portal); + buf.write_string(stmt); + + buf.write_be_i16_(formats.len() as i16); + for format in formats.iter() { + buf.write_be_i16_(*format); + } + + buf.write_be_i16_(values.len() as i16); + for value in values.iter() { + match *value { + None => { + buf.write_be_i16_(-1); + } + Some(value) => { + buf.write_be_i32_(value.len() as i32); + buf.write(value); + } + } + } + + buf.write_be_i16_(result_formats.len() as i16); + for format in result_formats.iter() { + buf.write_be_i16_(*format); + } + } + Close(variant, name) => { + ident = Some('C'); + buf.write_u8_(variant); + buf.write_string(name); + } + Describe(variant, name) => { ident = Some('D'); buf.write_u8_(variant); - buf.write_string(*name); + buf.write_string(name); } - Parse(ref name, ref query, ref param_types) => { + Parse(name, query, param_types) => { ident = Some('P'); - buf.write_string(*name); - buf.write_string(*query); + buf.write_string(name); + buf.write_string(query); buf.write_be_i16_(param_types.len() as i16); for ty in param_types.iter() { buf.write_be_i32_(*ty); } } - Query(ref query) => { + Query(query) => { ident = Some('Q'); - buf.write_string(*query); + buf.write_string(query); } StartupMessage(ref params) => { buf.write_be_i32_(PROTOCOL_VERSION); @@ -144,6 +183,8 @@ impl ReadMessage for R { let ret = match ident as char { '1' => ParseComplete, + '2' => BindComplete, + '3' => CloseComplete, 'E' => read_error_message(&mut buf), 'K' => BackendKeyData(buf.read_be_i32_(), buf.read_be_i32_()), 'n' => NoData, diff --git a/src/test.rs b/src/test.rs index 29649a90..82415619 100644 --- a/src/test.rs +++ b/src/test.rs @@ -8,4 +8,5 @@ fn test_connect() { "postgres"); let stmt = conn.prepare("CREATE TABLE foo (id BIGINT PRIMARY KEY)"); + stmt.query(); }