Skip to content

Commit 1b5051a

Browse files
committed
Share fetch array buffer when <Row as RowValue>::get() is called instead of deep copy.
This will improve performance pointed by #44.
1 parent 887efee commit 1b5051a

File tree

3 files changed

+48
-19
lines changed

3 files changed

+48
-19
lines changed

src/row.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ impl RowValue for Row {
261261
let num_cols = row.column_values.len();
262262
let mut column_values = Vec::with_capacity(num_cols);
263263
for val in &row.column_values {
264-
column_values.push(val.dup_by_handle()?);
264+
column_values.push(val.clone_except_fetch_array_buffer()?);
265265
}
266266
Ok(Row {
267267
column_info: row.column_info.clone(),

src/sql_value.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::convert::TryInto;
1717
use std::fmt;
1818
use std::os::raw::c_char;
1919
use std::ptr;
20+
use std::rc::Rc;
2021
use std::str;
2122
use std::sync::atomic::{AtomicU32, Ordering};
2223
use std::sync::Arc;
@@ -128,7 +129,7 @@ pub enum BufferRowIndex {
128129

129130
enum DpiData<'a> {
130131
Data(&'a mut dpiData),
131-
Var(DpiVar),
132+
Var(Rc<DpiVar>), // Rc is incremented only when <Row as RowValue>::get() is called.
132133
Null,
133134
}
134135

@@ -298,7 +299,7 @@ impl SqlValue<'_> {
298299
&mut data,
299300
)
300301
);
301-
self.data = DpiData::Var(DpiVar::new(handle, data));
302+
self.data = DpiData::Var(Rc::new(DpiVar::new(handle, data)));
302303
self.native_type = native_type;
303304
self.oratype = Some(oratype.clone());
304305
if native_type_num == DPI_NATIVE_TYPE_STMT {
@@ -322,7 +323,7 @@ impl SqlValue<'_> {
322323
);
323324
if num != 0 {
324325
self.array_size = num;
325-
self.data = DpiData::Var(DpiVar::with_add_ref(handle, data));
326+
self.data = DpiData::Var(Rc::new(DpiVar::with_add_ref(handle, data)));
326327
}
327328
Ok(())
328329
}
@@ -849,21 +850,31 @@ impl SqlValue<'_> {
849850
Ok(())
850851
}
851852

852-
pub(crate) fn dup_by_handle(&self) -> Result<SqlValue<'static>> {
853-
let mut val = SqlValue::new(
854-
self.conn.clone(),
855-
self.lob_bind_type,
856-
self.query_params.clone(),
857-
1,
858-
);
859-
if let Some(ref oratype) = self.oratype {
860-
val.init_handle(oratype)?;
861-
chkerr!(
862-
self.ctxt(),
863-
dpiVar_copyData(val.handle()?, 0, self.handle()?, self.buffer_row_index())
864-
);
853+
pub(crate) fn clone_except_fetch_array_buffer(&self) -> Result<SqlValue<'static>> {
854+
if let DpiData::Var(ref var) = self.data {
855+
Ok(SqlValue {
856+
conn: self.conn.clone(),
857+
data: DpiData::Var(var.clone()),
858+
native_type: self.native_type.clone(),
859+
oratype: self.oratype.clone(),
860+
array_size: self.array_size,
861+
buffer_row_index: BufferRowIndex::Owned(self.buffer_row_index()),
862+
keep_bytes: Vec::new(),
863+
keep_dpiobj: DpiObject::null(),
864+
lob_bind_type: self.lob_bind_type,
865+
query_params: self.query_params.clone(),
866+
})
867+
} else {
868+
Err(Error::internal_error("dpVar handle isn't initialized"))
869+
}
870+
}
871+
872+
pub(crate) fn fetch_array_buffer_shared_count(&self) -> Result<usize> {
873+
if let DpiData::Var(ref var) = self.data {
874+
Ok(Rc::strong_count(var))
875+
} else {
876+
Err(Error::internal_error("dpData isn't initialized"))
865877
}
866-
Ok(val)
867878
}
868879

869880
//

src/statement.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,13 +444,31 @@ impl Stmt {
444444
}
445445

446446
pub fn fetch_rows(&mut self) -> Result<bool> {
447+
let handle = self.handle();
448+
let row = self.row.as_mut().unwrap();
449+
for i in 0..(row.column_info.len()) {
450+
// If fetch array buffer is referenced only by self, it is reusable.
451+
// Otherwise, a new SqlValue must be created to allocate a new buffer
452+
// because dpiStmt_fetchRows() overwrites the buffer.
453+
if row.column_values[i].fetch_array_buffer_shared_count()? > 1 {
454+
let oratype = row.column_info[i].oracle_type();
455+
row.column_values[i] = SqlValue::for_column(
456+
self.conn.clone(),
457+
self.query_params.clone(),
458+
self.shared_buffer_row_index.clone(),
459+
oratype,
460+
handle,
461+
(i + 1) as u32,
462+
)?;
463+
}
464+
}
447465
let mut new_index = 0;
448466
let mut num_rows = 0;
449467
let mut more_rows = 0;
450468
chkerr!(
451469
self.ctxt(),
452470
dpiStmt_fetchRows(
453-
self.handle(),
471+
handle,
454472
self.query_params.fetch_array_size,
455473
&mut new_index,
456474
&mut num_rows,

0 commit comments

Comments
 (0)