Skip to content

Commit

Permalink
Merge pull request #130 from nao-kobayashi/modify-encoded-value
Browse files Browse the repository at this point in the history
fix parameter binding problem.
  • Loading branch information
Koka committed Nov 27, 2019
2 parents 8e726f4 + f56e72b commit 70d4fb2
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 8 deletions.
37 changes: 31 additions & 6 deletions src/statement/input.rs
@@ -1,6 +1,7 @@
use {ffi, Return, Result, Raii, Handle, Statement};
use super::types::OdbcType;
use odbc_safe::AutocommitMode;
use statement::types::EncodedValue;
use {ffi, Handle, Raii, Result, Return, Statement};

impl<'a, 'b, S, R, AC: AutocommitMode> Statement<'a, 'b, S, R, AC> {
/// Binds a parameter to a parameter marker in an SQL statement.
Expand Down Expand Up @@ -48,38 +49,62 @@ impl<'a, 'b, S, R, AC: AutocommitMode> Statement<'a, 'b, S, R, AC> {

let ind_ptr = self.param_ind_buffers.alloc(parameter_index as usize, ind);

//the result of value_ptr is changed per calling.
//binding and saving must have the same value.
let enc_value = value.encoded_value();

self.raii
.bind_input_parameter(parameter_index, value, ind_ptr)
.bind_input_parameter(parameter_index, value, ind_ptr, &enc_value)
.into_result(&self)?;

// save encoded value to avoid memory reuse.
if enc_value.has_value() {
self.encoded_values.push(enc_value);
}

Ok(self)
}

/// Releasing all parameter buffers set by `bind_parameter`. This method consumes the statement
/// and returns a new one those lifetime is no longer limited by the buffers bound.
pub fn reset_parameters(mut self) -> Result<Statement<'a, 'a, S, R, AC>> {
self.param_ind_buffers.clear();
self.encoded_values.clear();
self.raii.reset_parameters().into_result(&mut self)?;
Ok(Statement::with_raii(self.raii))
}
}

impl Raii<ffi::Stmt> {
fn bind_input_parameter<'c, T>(&mut self, parameter_index: u16, value: &'c T, str_len_or_ind_ptr: *mut ffi::SQLLEN) -> Return<()>
fn bind_input_parameter<'c, T>(
&mut self,
parameter_index: u16,
value: &'c T,
str_len_or_ind_ptr: *mut ffi::SQLLEN,
enc_value: &EncodedValue,
) -> Return<()>
where
T: OdbcType<'c>,
T: ?Sized,
{
//if encoded value exists, use it.
let (column_size, value_ptr) = if enc_value.has_value() {
(enc_value.column_size(), enc_value.value_ptr())
} else {
(value.column_size(), value.value_ptr())
};

match unsafe {
ffi::SQLBindParameter(
self.handle(),
parameter_index,
ffi::SQL_PARAM_INPUT,
T::c_data_type(),
T::sql_data_type(),
value.column_size(),
column_size,
value.decimal_digits(),
value.value_ptr(),
0, // buffer length
value_ptr,
0, // buffer length
str_len_or_ind_ptr, // Note that this ptr has to be valid until statement is executed
)
} {
Expand Down
7 changes: 5 additions & 2 deletions src/statement/mod.rs
Expand Up @@ -9,7 +9,7 @@ use ffi::SQLRETURN::*;
use ffi::Nullable;
use std::marker::PhantomData;
pub use self::types::OdbcType;
pub use self::types::{SqlDate, SqlTime, SqlSsTime2, SqlTimestamp};
pub use self::types::{SqlDate, SqlTime, SqlSsTime2, SqlTimestamp, EncodedValue};

// Allocate CHUNK_LEN elements at a time
const CHUNK_LEN: usize = 64;
Expand Down Expand Up @@ -76,6 +76,8 @@ pub struct Statement<'con, 'b, S, R, AC: AutocommitMode> {
result: PhantomData<R>,
parameters: PhantomData<&'b [u8]>,
param_ind_buffers: Chunks<ffi::SQLLEN>,
// encoded values are saved to use its pointer.
encoded_values: Vec<EncodedValue>,
}

/// Used to retrieve data from the fields of a query result
Expand Down Expand Up @@ -108,7 +110,8 @@ impl<'a, 'b, S, R, AC: AutocommitMode> Statement<'a, 'b, S, R, AC> {
state: PhantomData,
result: PhantomData,
parameters: PhantomData,
param_ind_buffers: Chunks::new()
param_ind_buffers: Chunks::new(),
encoded_values: Vec::new(),
}
}
}
Expand Down

0 comments on commit 70d4fb2

Please sign in to comment.