|
14 | 14 | //----------------------------------------------------------------------------- |
15 | 15 |
|
16 | 16 | use crate::private; |
| 17 | +use crate::sql_type::FromSql; |
17 | 18 | use crate::sql_type::OracleType; |
18 | 19 | use crate::sql_type::SqlValue; |
19 | 20 | use crate::sql_type::ToSql; |
20 | 21 | use crate::sql_type::ToSqlNull; |
21 | 22 | use crate::Connection; |
| 23 | +use crate::DpiVar; |
22 | 24 | use crate::Error; |
23 | 25 | use crate::ErrorKind; |
24 | 26 | use crate::Result; |
| 27 | +#[cfg(doc)] |
| 28 | +use crate::ResultSet; |
25 | 29 | use odpic_sys::*; |
26 | 30 | use std::fmt; |
27 | 31 | use std::os::raw::c_void; |
| 32 | +use std::rc::Rc; |
28 | 33 | use std::slice; |
29 | 34 |
|
30 | 35 | /// Vector dimension element format |
@@ -257,6 +262,84 @@ impl ToSql for VecRef<'_> { |
257 | 262 | } |
258 | 263 | } |
259 | 264 |
|
| 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 | + |
260 | 343 | /// Trait for vector dimension element type |
261 | 344 | /// |
262 | 345 | /// This trait is sealed and cannot be implemented for types outside of the `oracle` crate. |
@@ -335,6 +418,7 @@ impl VectorFormat for u8 { |
335 | 418 | mod tests { |
336 | 419 | use crate::sql_type::vector::VecFmt; |
337 | 420 | use crate::sql_type::vector::VecRef; |
| 421 | + use crate::sql_type::vector::Vector; |
338 | 422 | use crate::sql_type::OracleType; |
339 | 423 | use crate::test_util; |
340 | 424 | use crate::Result; |
@@ -488,4 +572,48 @@ mod tests { |
488 | 572 | assert_eq!(index, expected_data.len()); |
489 | 573 | Ok(()) |
490 | 574 | } |
| 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 | + } |
491 | 619 | } |
0 commit comments