Skip to content

Commit

Permalink
Merge pull request #137 from jpastuszek/raii_phantom
Browse files Browse the repository at this point in the history
moved PhantomData<'con> to Raii to prevent Raii drop after 'con drop when Statement bound to temporary at final expression in block
  • Loading branch information
Koka committed May 9, 2020
2 parents 19a1ae0 + 18f7015 commit f53fbf8
Show file tree
Hide file tree
Showing 10 changed files with 39 additions and 37 deletions.
2 changes: 1 addition & 1 deletion examples/custom_get_data.rs
Expand Up @@ -14,7 +14,7 @@ trait Extract {
T: MySupportedType;
}

impl<'a, S, AC: AutocommitMode> Extract for Cursor<'a, 'a, 'a, S, AC> {
impl<'s, 'a: 's, S: 's, AC: AutocommitMode> Extract for Cursor<'s, 'a, 'a, S, AC> {
fn extract<T>(&mut self, index: u16) -> Option<T>
where
T: MySupportedType,
Expand Down
18 changes: 12 additions & 6 deletions src/raii.rs
@@ -1,31 +1,35 @@
use super::{ffi, safe, DiagnosticRecord, GetDiagRec, Handle, OdbcObject, Return};
use std::ptr::null_mut;
use std::marker::PhantomData;

/// Wrapper around handle types which ensures the wrapped value is always valid.
///
/// Resource Acquisition Is Initialization
#[derive(Debug)]
pub struct Raii<T: OdbcObject> {
pub struct Raii<'p, T: OdbcObject> {
//Invariant: Should always point to a valid odbc Object
handle: *mut T,
// we use phantom data to tell the borrow checker that we need to keep the data source alive
// for the lifetime of the handle
parent: PhantomData<&'p ()>,
}

impl<T: OdbcObject> Handle for Raii<T> {
impl<'p, T: OdbcObject> Handle for Raii<'p, T> {
type To = T;
unsafe fn handle(&self) -> *mut T {
self.handle
}
}

unsafe impl<T: OdbcObject> safe::Handle for Raii<T> {
unsafe impl<'p, T: OdbcObject> safe::Handle for Raii<'p, T> {
const HANDLE_TYPE: ffi::HandleType = T::HANDLE_TYPE;

fn handle(&self) -> ffi::SQLHANDLE {
self.handle as ffi::SQLHANDLE
}
}

impl<T: OdbcObject> Drop for Raii<T> {
impl<'p, T: OdbcObject> Drop for Raii<'p, T> {
fn drop(&mut self) {
match unsafe { ffi::SQLFreeHandle(T::HANDLE_TYPE, self.handle() as ffi::SQLHANDLE) } {
ffi::SQL_SUCCESS => (),
Expand All @@ -38,8 +42,8 @@ impl<T: OdbcObject> Drop for Raii<T> {
}
}

impl<T: OdbcObject> Raii<T> {
pub fn with_parent<P>(parent: &P) -> Return<Self>
impl<'p, T: OdbcObject> Raii<'p, T> {
pub fn with_parent<P>(parent: &'p P) -> Return<Self>
where
P: Handle<To = T::Parent>,
{
Expand All @@ -53,9 +57,11 @@ impl<T: OdbcObject> Raii<T> {
} {
ffi::SQL_SUCCESS => Return::Success(Raii {
handle: handle as *mut T,
parent: PhantomData,
}),
ffi::SQL_SUCCESS_WITH_INFO => Return::SuccessWithInfo(Raii {
handle: handle as *mut T,
parent: PhantomData,
}),
ffi::SQL_ERROR => Return::Error,
_ => panic!("SQLAllocHandle returned unexpected result"),
Expand Down
2 changes: 1 addition & 1 deletion src/statement/input.rs
Expand Up @@ -75,7 +75,7 @@ impl<'a, 'b, S, R, AC: AutocommitMode> Statement<'a, 'b, S, R, AC> {
}
}

impl Raii<ffi::Stmt> {
impl<'p> Raii<'p, ffi::Stmt> {
fn bind_input_parameter<'c, T>(
&mut self,
parameter_index: u16,
Expand Down
24 changes: 11 additions & 13 deletions src/statement/mod.rs
Expand Up @@ -66,12 +66,10 @@ use std::ptr::null_mut;
use odbc_safe::AutocommitMode;

/// A `Statement` can be used to execute queries and retrieves results.
pub struct Statement<'con, 'b, S, R, AC: AutocommitMode> {
raii: Raii<ffi::Stmt>,
// we use phantom data to tell the borrow checker that we need to keep the data source alive
// for the lifetime of the statement
parent: PhantomData<&'con Connection<'con, AC>>,
pub struct Statement<'a, 'b, S, R, AC: AutocommitMode> {
raii: Raii<'a, ffi::Stmt>,
state: PhantomData<S>,
autocommit_mode: PhantomData<AC>,
// Indicates wether there is an open result set or not associated with this statement.
result: PhantomData<R>,
parameters: PhantomData<&'b [u8]>,
Expand All @@ -81,8 +79,8 @@ pub struct Statement<'con, 'b, S, R, AC: AutocommitMode> {
}

/// Used to retrieve data from the fields of a query result
pub struct Cursor<'a, 'b: 'a, 'c: 'a, S: 'a, AC: AutocommitMode> {
stmt: &'a mut Statement<'b, 'c, S, HasResult, AC>,
pub struct Cursor<'s, 'a: 's, 'b: 's, S: 's, AC: AutocommitMode> {
stmt: &'s mut Statement<'a, 'b, S, HasResult, AC>,
buffer: Vec<u8>,
}

Expand All @@ -103,10 +101,10 @@ impl<'a, 'b, S, R, AC: AutocommitMode> Handle for Statement<'a, 'b, S, R, AC> {
}

impl<'a, 'b, S, R, AC: AutocommitMode> Statement<'a, 'b, S, R, AC> {
fn with_raii(raii: Raii<ffi::Stmt>) -> Self {
fn with_raii(raii: Raii<'a, ffi::Stmt>) -> Self {
Statement {
raii: raii,
parent: PhantomData,
autocommit_mode: PhantomData,
state: PhantomData,
result: PhantomData,
parameters: PhantomData,
Expand Down Expand Up @@ -194,7 +192,7 @@ impl<'a, 'b, S, AC: AutocommitMode> Statement<'a, 'b, S, HasResult, AC> {
}

/// Fetches the next rowset of data from the result set and returns data for all bound columns.
pub fn fetch<'c>(&'c mut self) -> Result<Option<Cursor<'c, 'a, 'b, S, AC>>> {
pub fn fetch<'s>(&'s mut self) -> Result<Option<Cursor<'s, 'a, 'b, S, AC>>> {
if self.raii.fetch().into_result(self)? {
Ok(Some(Cursor {
stmt: self,
Expand Down Expand Up @@ -240,9 +238,9 @@ impl<'a, 'b, S, AC: AutocommitMode> Statement<'a, 'b, S, HasResult, AC> {

impl<'a, 'b, 'c, S, AC: AutocommitMode> Cursor<'a, 'b, 'c, S, AC> {
/// Retrieves data for a single column in the result set
///
///
/// ## Panics
///
///
/// If you try to convert to `&str` but the data can't be converted
/// without allocating an intermediate buffer.
pub fn get_data<'d, T>(&'d mut self, col_or_param_num: u16) -> Result<Option<T>>
Expand All @@ -253,7 +251,7 @@ impl<'a, 'b, 'c, S, AC: AutocommitMode> Cursor<'a, 'b, 'c, S, AC> {
}
}

impl Raii<ffi::Stmt> {
impl<'p> Raii<'p, ffi::Stmt> {
fn affected_row_count(&self) -> Return<ffi::SQLLEN> {
let mut count: ffi::SQLLEN = 0;
unsafe {
Expand Down
2 changes: 1 addition & 1 deletion src/statement/output.rs
Expand Up @@ -24,7 +24,7 @@ where
}
}

impl Raii<ffi::Stmt> {
impl<'p> Raii<'p, ffi::Stmt> {
fn get_data<'a, T>(
&mut self,
col_or_param_num: u16,
Expand Down
2 changes: 1 addition & 1 deletion src/statement/prepare.rs
Expand Up @@ -98,7 +98,7 @@ impl<'a, 'b, AC: AutocommitMode> Statement<'a, 'b, Prepared, NoResult, AC> {
}
}

impl Raii<ffi::Stmt> {
impl<'p> Raii<'p, ffi::Stmt> {
fn prepare(&mut self, sql_text: &str) -> Return<()> {
let bytes = unsafe { crate::environment::DB_ENCODING }.encode(sql_text).0;
match unsafe {
Expand Down
16 changes: 7 additions & 9 deletions tests/gbk.rs
Expand Up @@ -23,7 +23,7 @@ fn _exec_direct() {
}
} else {
panic!("SELECT did not return result set");
}
};
}

#[test]
Expand All @@ -48,8 +48,7 @@ fn _prepare_1() {
NoData(_) => {
panic!("SELECT did not return result set");
}
}

};
}

#[test]
Expand Down Expand Up @@ -77,7 +76,7 @@ fn _prepare_2() {
}
} else {
panic!("SELECT did not return result set");
}
};
}

#[test]
Expand All @@ -98,7 +97,7 @@ fn exec_direct() {
}
} else {
panic!("SELECT did not return result set");
}
};
}

#[test]
Expand All @@ -120,8 +119,7 @@ fn prepare_1() {
}
} else {
panic!("SELECT did not return result set");
}

};
}

/// CustomOdbcType for bindParameter
Expand Down Expand Up @@ -150,7 +148,7 @@ unsafe impl<'a> OdbcType<'a> for CustomOdbcType<'a> {
fn value_ptr(&self) -> ffi::SQLPOINTER {
self.data.as_ptr() as *const Self as ffi::SQLPOINTER
}

fn encoded_value(&self) -> EncodedValue {
EncodedValue::new(None)
}
Expand Down Expand Up @@ -180,5 +178,5 @@ fn prepare_2() {
}
} else {
panic!("SELECT did not return result set");
}
};
}
2 changes: 1 addition & 1 deletion tests/input_parameter.rs
Expand Up @@ -25,7 +25,7 @@ macro_rules! test_type {
}
}else{
panic!("SELECT did not return result set");
}
};
})
}

Expand Down
6 changes: 3 additions & 3 deletions tests/libs.rs
Expand Up @@ -329,7 +329,7 @@ fn zero_truncation_bug() {
NoData(stmt) => stmt,
};
// Reproduction of zeroes truncation bug. Until now there is no chance to query binary data
// with zero at 512 byte border.
// with zero at 512 byte border.
let data = vec![0;513];
stmt
.prepare("INSERT INTO ZERO_TRUNCATION_BUG VALUES (?)")
Expand All @@ -349,5 +349,5 @@ fn zero_truncation_bug() {
stmt.exec_direct("DROP TABLE ZERO_TRUNCATION_BUG").unwrap();
} else {
panic!("SELECT statement returned no result set")
}
}
};
}
2 changes: 1 addition & 1 deletion tests/native_types.rs
Expand Up @@ -24,7 +24,7 @@ macro_rules! test_type {
}
} else {
panic!("SELECT did not return result set");
}
};
})
}

Expand Down

0 comments on commit f53fbf8

Please sign in to comment.