Skip to content

Commit 21fef44

Browse files
committed
Add module-level document for vector data type
1 parent 88be7c7 commit 21fef44

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

src/sql_type/vector.rs

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,189 @@
1313
// (ii) the Apache License v 2.0. (http://www.apache.org/licenses/LICENSE-2.0)
1414
//-----------------------------------------------------------------------------
1515

16+
//! VECTOR data type support
17+
//!
18+
//! Oracle Database 23ai introduced a new data type [VECTOR]. This module contains
19+
//! rust types to support the Oracle type.
20+
//!
21+
//! In short:
22+
//! * Insert VECTOR data by wrapping slice data such as `&[f32]` in [`VecRef`].
23+
//! * Fetch VECTOR data as `Vec<_>` such as `Vec<f32>` when the vector dimension element format is known.
24+
//! * Fetch VECTOR data as [`Vector`] type when the vector dimension element format is unknown.
25+
//! * Fetch VECTOR data as [`Vector`] type when the method to be called takes a slice
26+
//! as an argument and you want to avoid the cost of memory allocation for `Vec<_>`.
27+
//!
28+
//! # Note
29+
//!
30+
//! Fetched [`Vector`] data should be dropped before the next fetch. That's because [`Vector`] and [`ResultSet`]
31+
//! share an internal fetch buffer. When the next row is fetched from the result set and the vector
32+
//! is alive and has a reference to the buffer, a new fetch buffer may be allocated. When the vector is dropped,
33+
//! and only the result set has the reference, it is reused.
34+
//!
35+
//! # Examples
36+
//!
37+
//! Wrap slice data in [`VecRef`] to insert VECTOR data.
38+
//!
39+
//! ```
40+
//! # use oracle::test_util;
41+
//! # use oracle::sql_type::vector::VecRef;
42+
//! # let conn = test_util::connect()?;
43+
//! # if !test_util::check_version(&conn, &test_util::VER23, &test_util::VER23)? {
44+
//! # return Ok(());
45+
//! # }
46+
//! let mut stmt = conn
47+
//! .statement("insert into test_vector_type(id, vec) values (:1, :2)")
48+
//! .build()?;
49+
//! // Insert &[f32] slice as Oracle type VECTOR(FLOAT32, 3).
50+
//! stmt.execute(&[&1, &VecRef::Float32(&[0.0001, 100.0, 3.4])])?;
51+
//!
52+
//! // Insert &[f64] slice as Oracle type VECTOR(FLOAT64, 3).
53+
//! stmt.execute(&[&2, &VecRef::Float64(&[5.6, 1000.3, 0.0838])])?;
54+
//!
55+
//! // Insert &[i8] slice as Oracle type VECTOR(INT8, 3).
56+
//! stmt.execute(&[&3, &VecRef::Int8(&[1, 100, -30])])?;
57+
//!
58+
//! # if test_util::check_version(&conn, &test_util::VER23_5, &test_util::VER23_5)? {
59+
//! // Insert &[u8] slice as Oracle type VECTOR(BINARY, 24).
60+
//! // Binary vectors require the database initialization parameter COMPATIBLE
61+
//! // to be set to 23.5.0.0.0 or greater on Oracle Database.
62+
//! stmt.execute(&[&4, &VecRef::Binary(&[128, 0, 225])])?;
63+
//! # }
64+
//! # Ok::<(), Box<dyn std::error::Error>>(())
65+
//! ```
66+
//!
67+
//! Fetch VECTOR data as `Vec<_>` when the vector dimension element format is known.
68+
//!
69+
//! ```
70+
//! # use oracle::test_util;
71+
//! # use oracle::sql_type::vector::VecRef;
72+
//! # let conn = test_util::connect()?;
73+
//! # if !test_util::check_version(&conn, &test_util::VER23, &test_util::VER23)? {
74+
//! # return Ok(());
75+
//! # }
76+
//! # let mut stmt = conn
77+
//! # .statement("insert into test_vector_type(id, vec) values (:1, :2)")
78+
//! # .build()?;
79+
//! # stmt.execute(&[&1, &VecRef::Float32(&[0.0001, 100.0, 3.4])])?;
80+
//! # stmt.execute(&[&2, &VecRef::Float64(&[5.6, 1000.3, 0.0838])])?;
81+
//! # stmt.execute(&[&3, &VecRef::Int8(&[1, 100, -30])])?;
82+
//! # if test_util::check_version(&conn, &test_util::VER23_5, &test_util::VER23_5)? {
83+
//! # stmt.execute(&[&4, &VecRef::Binary(&[128, 0, 225])])?;
84+
//! # }
85+
//! // Fetch VECTOR(FLOAT32) data as Vec<f32>
86+
//! let f32_vec = conn.query_row_as::<Vec<f32>>("select vec from test_vector_type where id = :1", &[&1])?;
87+
//! assert_eq!(f32_vec, vec![0.0001, 100.0, 3.4]);
88+
//!
89+
//! // Fetch VECTOR(FLOAT64) data as Vec<f64>
90+
//! let f64_vec = conn.query_row_as::<Vec<f64>>("select vec from test_vector_type where id = :1", &[&2])?;
91+
//! assert_eq!(f64_vec, vec![5.6, 1000.3, 0.0838]);
92+
//!
93+
//! // Fetch VECTOR(INT8) data as Vec<i8>
94+
//! let i8_vec = conn.query_row_as::<Vec<i8>>("select vec from test_vector_type where id = :1", &[&3])?;
95+
//! assert_eq!(i8_vec, vec![1, 100, -30]);
96+
//!
97+
//! # if test_util::check_version(&conn, &test_util::VER23_5, &test_util::VER23_5)? {
98+
//! // Fetch VECTOR(BINARY) data as Vec<u8>
99+
//! let binary_vec = conn.query_row_as::<Vec<u8>>("select vec from test_vector_type where id = :1", &[&4])?;
100+
//! assert_eq!(binary_vec, vec![128, 0, 225]);
101+
//! # }
102+
//! # Ok::<(), Box<dyn std::error::Error>>(())
103+
//! ```
104+
//!
105+
//! Fetch VECTOR data as [`Vector`] type and check the dimension element format.
106+
//!
107+
//! ```
108+
//! # use oracle::test_util;
109+
//! # use oracle::sql_type::vector::VecRef;
110+
//! # use oracle::sql_type::vector::Vector;
111+
//! # let conn = test_util::connect()?;
112+
//! # if !test_util::check_version(&conn, &test_util::VER23, &test_util::VER23)? {
113+
//! # return Ok(());
114+
//! # }
115+
//! # let mut stmt = conn
116+
//! # .statement("insert into test_vector_type(id, vec) values (:1, :2)")
117+
//! # .build()?;
118+
//! # stmt.execute(&[&1, &VecRef::Float32(&[0.0001, 100.0, 3.4])])?;
119+
//! # stmt.execute(&[&2, &VecRef::Float64(&[5.6, 1000.3, 0.0838])])?;
120+
//! # stmt.execute(&[&3, &VecRef::Int8(&[1, 100, -30])])?;
121+
//! # if test_util::check_version(&conn, &test_util::VER23_5, &test_util::VER23_5)? {
122+
//! # stmt.execute(&[&4, &VecRef::Binary(&[128, 0, 225])])?;
123+
//! # }
124+
//! let mut rows = conn.query_as::<(i32, Vector)>("select id, vec from test_vector_type", &[])?;
125+
//! for row_result in rows {
126+
//! let (id, vector) = row_result?;
127+
//! // Check the vector dimension element type at runtime.
128+
//! match vector.as_vec_ref() {
129+
//! // When id == 1, the vector data type is VECTOR(FLOAT32, 3).
130+
//! VecRef::Float32(slice) => {
131+
//! assert_eq!(id, 1);
132+
//! assert_eq!(slice, &[0.0001, 100.0, 3.4]);
133+
//! },
134+
//! // When id == 2, the vector data type is VECTOR(FLOAT64, 3).
135+
//! VecRef::Float64(slice) => {
136+
//! assert_eq!(id, 2);
137+
//! assert_eq!(slice, &[5.6, 1000.3, 0.0838]);
138+
//! },
139+
//! // When id == 3, the vector data type is VECTOR(INT8, 3).
140+
//! VecRef::Int8(slice) => {
141+
//! assert_eq!(id, 3);
142+
//! assert_eq!(slice, &[1, 100, -30]);
143+
//! },
144+
//! // When id == 4, the vector data type is VECTOR(BIANRY, 24).
145+
//! VecRef::Binary(slice) => {
146+
//! assert_eq!(id, 4);
147+
//! assert_eq!(slice, &[128, 0, 225]);
148+
//! },
149+
//! _ => panic!("unexpected format {}", vector.format()),
150+
//! }
151+
//! }
152+
//! # Ok::<(), Box<dyn std::error::Error>>(())
153+
//! ```
154+
//!
155+
//! Fetch VECTOR data as [`Vector`] type and get a reference to the internal
156+
//! array data held by [`ResultSet`]. Use this when the method to be called takes a slice
157+
//! as the vector data.
158+
//!
159+
//! ```
160+
//! # use oracle::test_util;
161+
//! # use oracle::sql_type::vector::VecRef;
162+
//! # use oracle::sql_type::vector::Vector;
163+
//! // Assume that you have a vector type
164+
//! struct YourVectorType {
165+
//! // ...
166+
//! }
167+
//!
168+
//! // The vector type has a method taking &[f32] slice
169+
//! // but doesn't have a method taking Vec<f32>.
170+
//! impl YourVectorType {
171+
//! pub fn from_slice(slice: &[f32]) -> YourVectorType {
172+
//! // ...
173+
//! # assert_eq!(slice, &[0.0001, 100.0, 3.4]);
174+
//! # YourVectorType{}
175+
//! }
176+
//! }
177+
//!
178+
//! # let conn = test_util::connect()?;
179+
//! # if !test_util::check_version(&conn, &test_util::VER23, &test_util::VER23)? {
180+
//! # return Ok(());
181+
//! # }
182+
//! # let mut stmt = conn
183+
//! # .statement("insert into test_vector_type(id, vec) values (:1, :2)")
184+
//! # .build()?;
185+
//! # stmt.execute(&[&1, &VecRef::Float32(&[0.0001, 100.0, 3.4])])?;
186+
//! // The following code is inefficient. That's becuase `Vec<f32>` is allocated
187+
//! // only to be passed to from_slice().
188+
//! let vec = conn.query_row_as::<Vec<f32>>("select vec from test_vector_type where id = :1", &[&1])?;
189+
//! YourVectorType::from_slice(&vec);
190+
//!
191+
//! // The following code avoids memory allocation to create a temporary Vec data.
192+
//! let vec = conn.query_row_as::<Vector>("select vec from test_vector_type where id = :1", &[&1])?;
193+
//! YourVectorType::from_slice(vec.as_slice()?);
194+
//! # Ok::<(), Box<dyn std::error::Error>>(())
195+
//! ```
196+
//!
197+
//! [VECTOR]: https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/overview-ai-vector-search.html
198+
16199
use crate::private;
17200
use crate::sql_type::FromSql;
18201
use crate::sql_type::OracleType;

0 commit comments

Comments
 (0)