|
13 | 13 | // (ii) the Apache License v 2.0. (http://www.apache.org/licenses/LICENSE-2.0) |
14 | 14 | //----------------------------------------------------------------------------- |
15 | 15 |
|
| 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 | +
|
16 | 199 | use crate::private; |
17 | 200 | use crate::sql_type::FromSql; |
18 | 201 | use crate::sql_type::OracleType; |
|
0 commit comments