diff --git a/src/lib.rs b/src/lib.rs index 1bf0e13d..b3e2a979 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,7 @@ use std::io::prelude::*; use std::marker::Sync as StdSync; use std::mem; use std::result; +use std::sync::Arc; use std::time::Duration; #[cfg(feature = "unix_socket")] use std::path::PathBuf; @@ -361,8 +362,7 @@ pub enum SslMode<'a> { Require(&'a NegotiateSsl), } -#[derive(Clone)] -struct CachedStatement { +struct StatementInfo { name: String, param_types: Vec, columns: Vec, @@ -374,7 +374,7 @@ struct InnerConnection { notifications: VecDeque, cancel_data: CancelData, unknown_types: HashMap, - cached_statements: HashMap, + cached_statements: HashMap>, parameters: HashMap, next_stmt_id: u32, trans_depth: u32, @@ -670,28 +670,33 @@ impl InnerConnection { fn prepare<'a>(&mut self, query: &str, conn: &'a Connection) -> Result> { let stmt_name = self.make_stmt_name(); let (param_types, columns) = try!(self.raw_prepare(&stmt_name, query)); - Ok(Statement::new(conn, stmt_name, param_types, columns, Cell::new(0), false)) + let info = Arc::new(StatementInfo { + name: stmt_name, + param_types: param_types, + columns: columns, + }); + Ok(Statement::new(conn, info, Cell::new(0), false)) } fn prepare_cached<'a>(&mut self, query: &str, conn: &'a Connection) -> Result> { - let stmt = self.cached_statements.get(query).cloned(); + let info = self.cached_statements.get(query).cloned(); - let CachedStatement { name, param_types, columns } = match stmt { - Some(stmt) => stmt, + let info = match info { + Some(info) => info, None => { let stmt_name = self.make_stmt_name(); let (param_types, columns) = try!(self.raw_prepare(&stmt_name, query)); - let stmt = CachedStatement { + let info = Arc::new(StatementInfo { name: stmt_name, param_types: param_types, columns: columns, - }; - self.cached_statements.insert(query.to_owned(), stmt.clone()); - stmt + }); + self.cached_statements.insert(query.to_owned(), info.clone()); + info } }; - Ok(Statement::new(conn, name, param_types, columns, Cell::new(0), true)) + Ok(Statement::new(conn, info, Cell::new(0), true)) } fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> { @@ -959,12 +964,12 @@ impl Connection { /// ``` pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result { let (param_types, columns) = try!(self.conn.borrow_mut().raw_prepare("", query)); - let stmt = Statement::new(self, - "".to_owned(), - param_types, - columns, - Cell::new(0), - true); + let info = Arc::new(StatementInfo { + name: String::new(), + param_types: param_types, + columns: columns, + }); + let stmt = Statement::new(self, info, Cell::new(0), true); stmt.execute(params) } @@ -995,12 +1000,12 @@ impl Connection { /// ``` pub fn query<'a>(&'a self, query: &str, params: &[&ToSql]) -> Result> { let (param_types, columns) = try!(self.conn.borrow_mut().raw_prepare("", query)); - let stmt = Statement::new(self, - "".to_owned(), - param_types, - columns, - Cell::new(0), - true); + let info = Arc::new(StatementInfo { + name: String::new(), + param_types: param_types, + columns: columns, + }); + let stmt = Statement::new(self, info, Cell::new(0), true); stmt.into_query(params) } @@ -1497,9 +1502,7 @@ trait SessionInfoNew<'a> { trait StatementInternals<'conn> { fn new(conn: &'conn Connection, - name: String, - param_types: Vec, - columns: Vec, + info: Arc, next_portal_id: Cell, finished: bool) -> Statement<'conn>; diff --git a/src/stmt.rs b/src/stmt.rs index 644ea23c..8d43079e 100644 --- a/src/stmt.rs +++ b/src/stmt.rs @@ -4,6 +4,7 @@ use std::cell::{Cell, RefMut}; use std::collections::VecDeque; use std::fmt; use std::io::{self, Read, Write}; +use std::sync::Arc; use error::{Error, DbError}; use types::{SessionInfo, Type, ToSql, IsNull}; @@ -13,14 +14,12 @@ use message::WriteMessage; use util; use rows::{Rows, LazyRows}; use {read_rows, bad_response, Connection, Transaction, StatementInternals, Result, RowsNew}; -use {InnerConnection, SessionInfoNew, LazyRowsNew, DbErrorNew, ColumnNew}; +use {InnerConnection, SessionInfoNew, LazyRowsNew, DbErrorNew, ColumnNew, StatementInfo}; /// A prepared statement. pub struct Statement<'conn> { conn: &'conn Connection, - name: String, - param_types: Vec, - columns: Vec, + info: Arc, next_portal_id: Cell, finished: bool, } @@ -28,9 +27,9 @@ pub struct Statement<'conn> { impl<'a> fmt::Debug for Statement<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Statement") - .field("name", &self.name) - .field("parameter_types", &self.param_types) - .field("columns", &self.columns) + .field("name", &self.info.name) + .field("parameter_types", &self.info.param_types) + .field("columns", &self.info.columns) .finish() } } @@ -43,17 +42,13 @@ impl<'conn> Drop for Statement<'conn> { impl<'conn> StatementInternals<'conn> for Statement<'conn> { fn new(conn: &'conn Connection, - name: String, - param_types: Vec, - columns: Vec, + info: Arc, next_portal_id: Cell, finished: bool) -> Statement<'conn> { Statement { conn: conn, - name: name, - param_types: param_types, - columns: columns, + info: info, next_portal_id: next_portal_id, finished: finished, } @@ -76,7 +71,7 @@ impl<'conn> Statement<'conn> { self.finished = true; let mut conn = self.conn.conn.borrow_mut(); check_desync!(conn); - conn.close_statement(&self.name, b'S') + conn.close_statement(&self.info.name, b'S') } else { Ok(()) } @@ -86,13 +81,13 @@ impl<'conn> Statement<'conn> { let mut conn = self.conn.conn.borrow_mut(); assert!(self.param_types().len() == params.len(), "expected {} parameters but got {}", - self.param_types.len(), + self.param_types().len(), params.len()); debug!("executing statement {} with parameters: {:?}", - self.name, + self.info.name, params); let mut values = vec![]; - for (param, ty) in params.iter().zip(self.param_types.iter()) { + for (param, ty) in params.iter().zip(self.param_types()) { let mut buf = vec![]; match try!(param.to_sql_checked(ty, &mut buf, &SessionInfo::new(&*conn))) { IsNull::Yes => values.push(None), @@ -102,7 +97,7 @@ impl<'conn> Statement<'conn> { try!(conn.write_messages(&[Bind { portal: portal_name, - statement: &self.name, + statement: &self.info.name, formats: &[1], values: &values, result_formats: &[1], @@ -140,12 +135,12 @@ impl<'conn> Statement<'conn> { /// Returns a slice containing the expected parameter types. pub fn param_types(&self) -> &[Type] { - &self.param_types + &self.info.param_types } /// Returns a slice describing the columns of the result of the query. pub fn columns(&self) -> &[Column] { - &self.columns + &self.info.columns } /// Executes the prepared statement, returning the number of rows modified. @@ -279,7 +274,7 @@ impl<'conn> Statement<'conn> { let id = self.next_portal_id.get(); self.next_portal_id.set(id + 1); - let portal_name = format!("{}p{}", self.name, id); + let portal_name = format!("{}p{}", self.info.name, id); self.inner_query(&portal_name, row_limit, params).map(move |(data, more_rows)| { LazyRows::new(self, data, portal_name, row_limit, more_rows, false, trans)