Skip to content

Commit 88be7c7

Browse files
committed
Add Vector struct to get rust values from VECTOR data type
1 parent 620305a commit 88be7c7

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

ChangeLog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ New features:
99
* Add [`InnerValue::Vector`] variant
1010
* Add [`VecFmt`] enum type
1111
* Add [`VecRef`] enum type to set rust values to Oracle VECTOR data type
12+
* Add [`Vector`] struct to get rust values from Oracle VECTOR data type
1213
* Add [`VectorFormat`] trait type
1314
* impl `FromSql` for `Vec<f32>`, `Vec<f64>`, `Vec<i8>` and `Vec<u8>` to get values from Oracle VECTOR data type
1415

@@ -602,4 +603,5 @@ Incompatible changes:
602603
[`Timestamp::new()`]: https://www.jiubao.org/rust-oracle/oracle/sql_type/struct.Timestamp.html#method.new
603604
[`VecFmt`]: https://www.jiubao.org/rust-oracle/oracle/sql_type/vector/enum.VecFmt.html
604605
[`VecRef`]: https://www.jiubao.org/rust-oracle/oracle/sql_type/vector/enum.VecRef.html
606+
[`Vector`]: https://www.jiubao.org/rust-oracle/oracle/sql_type/vector/struct.Vector.html
605607
[`VectorFormat`]: https://www.jiubao.org/rust-oracle/oracle/sql_type/vector/trait.VectorFormat.html

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ define_dpi_data_with_refcount!(Object, nosync);
170170
define_dpi_data_with_refcount!(Stmt, nosync);
171171

172172
// define DpiVar wrapping *mut dpiVar.
173+
#[derive(Debug)]
173174
struct DpiVar {
174175
raw: *mut dpiVar,
175176
data: *mut dpiData,

src/sql_type/vector.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,22 @@
1414
//-----------------------------------------------------------------------------
1515

1616
use crate::private;
17+
use crate::sql_type::FromSql;
1718
use crate::sql_type::OracleType;
1819
use crate::sql_type::SqlValue;
1920
use crate::sql_type::ToSql;
2021
use crate::sql_type::ToSqlNull;
2122
use crate::Connection;
23+
use crate::DpiVar;
2224
use crate::Error;
2325
use crate::ErrorKind;
2426
use crate::Result;
27+
#[cfg(doc)]
28+
use crate::ResultSet;
2529
use odpic_sys::*;
2630
use std::fmt;
2731
use std::os::raw::c_void;
32+
use std::rc::Rc;
2833
use std::slice;
2934

3035
/// Vector dimension element format
@@ -257,6 +262,84 @@ impl ToSql for VecRef<'_> {
257262
}
258263
}
259264

265+
/// Vector data retrieved from the Oracle database
266+
///
267+
/// See the [module-level documentation](index.html) for more.
268+
///
269+
/// # Note
270+
///
271+
/// Fetched [`Vector`] data should be dropped before the next fetch. That's because [`Vector`] and [`ResultSet`]
272+
/// share an internal fetch buffer. When the next row is fetched from the result set and the vector
273+
/// is alive and has a reference to the buffer, a new fetch buffer may be allocated. When the vector is dropped,
274+
/// and only the result set has the reference, it is reused.
275+
#[derive(Debug)]
276+
pub struct Vector {
277+
// The 'static lifetime is incorrect. Its actual lifetime is same with DpiVar.
278+
vec_ref: VecRef<'static>,
279+
// _var must be held until the end of lifetime.
280+
// Otherwise vec_ref may points to freed memory region.
281+
_var: Rc<DpiVar>,
282+
}
283+
284+
impl Vector {
285+
pub(crate) fn new(vec_ref: VecRef<'static>, var: Rc<DpiVar>) -> Result<Vector> {
286+
Ok(Vector { vec_ref, _var: var })
287+
}
288+
289+
/// Returns vector dimension element format.
290+
///
291+
/// **Note:** It doesn't return `VecFmt::Flexible`.
292+
pub fn format(&self) -> VecFmt {
293+
self.vec_ref.format()
294+
}
295+
296+
/// Returns the internal [`VecRef`] data.
297+
pub fn as_vec_ref(&self) -> &VecRef {
298+
&self.vec_ref
299+
}
300+
301+
/// Gets the containing vector data as slice
302+
///
303+
/// # Examples
304+
///
305+
/// ```
306+
/// # use oracle::test_util;
307+
/// # use oracle::sql_type::vector::VecRef;
308+
/// # use oracle::sql_type::vector::Vector;
309+
/// # let conn = test_util::connect()?;
310+
/// # if !test_util::check_version(&conn, &test_util::VER23, &test_util::VER23)? {
311+
/// # return Ok(());
312+
/// # }
313+
/// # let mut stmt = conn
314+
/// # .statement("insert into test_vector_type(id, vec) values (:1, :2)")
315+
/// # .build()?;
316+
/// # stmt.execute(&[&1, &VecRef::Float32(&[0.0001, 100.0, 3.4])])?;
317+
/// // Fetch VECTOR(FLOAT32) data from Oracle.
318+
/// let vec = conn.query_row_as::<Vector>("select vec from test_vector_type where id = 1", &[])?;
319+
///
320+
/// // Gets as a slice of [f32]
321+
/// assert_eq!(vec.as_slice::<f32>()?, &[0.0001, 100.0, 3.4]);
322+
///
323+
/// // Fails for other types.
324+
/// assert!(vec.as_slice::<f64>().is_err());
325+
/// assert!(vec.as_slice::<i8>().is_err());
326+
/// assert!(vec.as_slice::<u8>().is_err());
327+
/// # Ok::<(), Box<dyn std::error::Error>>(())
328+
/// ```
329+
pub fn as_slice<T>(&self) -> Result<&[T]>
330+
where
331+
T: VectorFormat,
332+
{
333+
T::vec_ref_to_slice(&self.vec_ref)
334+
}
335+
}
336+
337+
impl FromSql for Vector {
338+
fn from_sql(val: &SqlValue) -> Result<Vector> {
339+
val.to_vector()
340+
}
341+
}
342+
260343
/// Trait for vector dimension element type
261344
///
262345
/// This trait is sealed and cannot be implemented for types outside of the `oracle` crate.
@@ -335,6 +418,7 @@ impl VectorFormat for u8 {
335418
mod tests {
336419
use crate::sql_type::vector::VecFmt;
337420
use crate::sql_type::vector::VecRef;
421+
use crate::sql_type::vector::Vector;
338422
use crate::sql_type::OracleType;
339423
use crate::test_util;
340424
use crate::Result;
@@ -488,4 +572,48 @@ mod tests {
488572
assert_eq!(index, expected_data.len());
489573
Ok(())
490574
}
575+
576+
#[test]
577+
fn vector_from_sql() -> Result<()> {
578+
let conn = test_util::connect()?;
579+
580+
if !test_util::check_version(&conn, &test_util::VER23, &test_util::VER23)? {
581+
return Ok(());
582+
}
583+
let binary_vec = test_util::check_version(&conn, &test_util::VER23_5, &test_util::VER23_5)?;
584+
conn.execute("delete from test_vector_type", &[])?;
585+
let mut expected_data = vec![];
586+
conn.execute("insert into test_vector_type(id, vec) values(1, TO_VECTOR('[1.0, 2.25, 3.5]', 3, FLOAT32))", &[])?;
587+
expected_data.push((1, "FLOAT32", VecRef::Float32(&[1.0, 2.25, 3.5])));
588+
conn.execute("insert into test_vector_type(id, vec) values(2, TO_VECTOR('[4.0, 5.25, 6.5]', 3, FLOAT64))", &[])?;
589+
expected_data.push((2, "FLOAT64", VecRef::Float64(&[4.0, 5.25, 6.5])));
590+
conn.execute(
591+
"insert into test_vector_type(id, vec) values(3, TO_VECTOR('[7, 8, 9]', 3, INT8))",
592+
&[],
593+
)?;
594+
expected_data.push((3, "INT8", VecRef::Int8(&[7, 8, 9])));
595+
if binary_vec {
596+
conn.execute("insert into test_vector_type(id, vec) values(4, TO_VECTOR('[10, 11, 12]', 24, BINARY))", &[])?;
597+
expected_data.push((4, "BINARY", VecRef::Binary(&[10, 11, 12])));
598+
}
599+
let rows = conn
600+
.statement(
601+
"select id, vector_dimension_format(vec), vec from test_vector_type order by id",
602+
)
603+
.fetch_array_size(2) // This must be lower than number of total rows in order to check Vector holds `_var`.
604+
.build()?
605+
.query_as::<(i32, String, Vector)>(&[])?
606+
.collect::<Result<Vec<_>>>()?;
607+
let mut index = 0;
608+
for row in rows {
609+
assert!(index < expected_data.len());
610+
let data = &expected_data[index];
611+
assert_eq!(row.0, data.0);
612+
assert_eq!(row.1, data.1);
613+
assert_eq!(row.2.as_vec_ref(), &data.2);
614+
index += 1;
615+
}
616+
assert_eq!(index, expected_data.len());
617+
Ok(())
618+
}
491619
}

src/sql_value.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::chkerr;
1717
use crate::connection::Conn;
1818
use crate::sql_type::vector::VecFmt;
1919
use crate::sql_type::vector::VecRef;
20+
use crate::sql_type::vector::Vector;
2021
use crate::sql_type::Bfile;
2122
use crate::sql_type::Blob;
2223
use crate::sql_type::Clob;
@@ -1296,6 +1297,21 @@ impl SqlValue<'_> {
12961297
}
12971298
}
12981299

1300+
pub(crate) fn to_vector(&self) -> Result<Vector> {
1301+
let var = if let DpiData::Var(var) = &self.data {
1302+
var.clone()
1303+
} else {
1304+
return Err(Error::internal_error("dpVar handle isn't initialized"));
1305+
};
1306+
match self.native_type {
1307+
NativeType::Vector => unsafe {
1308+
let vec_ref = self.get_vec_ref_unchecked()?;
1309+
Vector::new(vec_ref, var)
1310+
},
1311+
_ => self.invalid_conversion_to_rust_type("Vector"),
1312+
}
1313+
}
1314+
12991315
//
13001316
// set_TYPE methods
13011317
//

0 commit comments

Comments
 (0)