odbc_api/buffers/column_with_indicator.rs
1use crate::{
2 fixed_sized::{Bit, Pod},
3 handles::{CData, CDataMut},
4};
5use odbc_sys::{Date, Time, Timestamp, NULL_DATA};
6use std::{
7 ffi::c_void,
8 mem::size_of,
9 ptr::{null, null_mut},
10};
11
12pub type OptF64Column = ColumnWithIndicator<f64>;
13pub type OptF32Column = ColumnWithIndicator<f32>;
14pub type OptDateColumn = ColumnWithIndicator<Date>;
15pub type OptTimestampColumn = ColumnWithIndicator<Timestamp>;
16pub type OptTimeColumn = ColumnWithIndicator<Time>;
17pub type OptI8Column = ColumnWithIndicator<i8>;
18pub type OptI16Column = ColumnWithIndicator<i16>;
19pub type OptI32Column = ColumnWithIndicator<i32>;
20pub type OptI64Column = ColumnWithIndicator<i64>;
21pub type OptU8Column = ColumnWithIndicator<u8>;
22pub type OptBitColumn = ColumnWithIndicator<Bit>;
23
24/// Column buffer for fixed sized type, also binding an indicator buffer to handle NULL.
25#[derive(Debug)]
26pub struct ColumnWithIndicator<T> {
27 values: Vec<T>,
28 indicators: Vec<isize>,
29}
30
31impl<T> ColumnWithIndicator<T>
32where
33 T: Default + Clone,
34{
35 pub fn new(batch_size: usize) -> Self {
36 Self {
37 values: vec![T::default(); batch_size],
38 indicators: vec![NULL_DATA; batch_size],
39 }
40 }
41
42 /// Access the value at a specific row index.
43 ///
44 /// The buffer size is not automatically adjusted to the size of the last row set. It is the
45 /// callers responsibility to ensure, a value has been written to the indexed position by
46 /// [`crate::Cursor::fetch`] using the value bound to the cursor with
47 /// [`crate::Cursor::set_num_result_rows_fetched`].
48 pub fn iter(&self, num_rows: usize) -> NullableSlice<'_, T> {
49 NullableSlice {
50 indicators: &self.indicators[0..num_rows],
51 values: &self.values[0..num_rows],
52 }
53 }
54
55 /// Fills the column with NULL, between From and To
56 pub fn fill_null(&mut self, from: usize, to: usize) {
57 for index in from..to {
58 self.indicators[index] = NULL_DATA;
59 }
60 }
61
62 /// Create a writer which writes to the first `n` elements of the buffer.
63 pub fn writer_n(&mut self, n: usize) -> NullableSliceMut<'_, T> {
64 NullableSliceMut {
65 indicators: &mut self.indicators[0..n],
66 values: &mut self.values[0..n],
67 }
68 }
69
70 /// Maximum number elements which the column may hold.
71 pub fn capacity(&self) -> usize {
72 self.indicators.len()
73 }
74}
75
76/// Iterates over the elements of a column buffer. Returned by
77/// [`crate::buffers::ColumnarBuffer::column`] as part of an [`crate::buffers::AnySlice`].
78#[derive(Debug, Clone, Copy)]
79pub struct NullableSlice<'a, T> {
80 indicators: &'a [isize],
81 values: &'a [T],
82}
83
84impl<'a, T> NullableSlice<'a, T> {
85 /// `true` if the slice has a length of `0`.
86 pub fn is_empty(&self) -> bool {
87 self.values.is_empty()
88 }
89
90 /// Number of entries in this slice of the buffer
91 pub fn len(&self) -> usize {
92 self.values.len()
93 }
94
95 /// Read access to the underlying raw value and indicator buffer.
96 ///
97 /// The number of elements in the buffer is equal to the number of rows returned in the current
98 /// result set. Yet the content of any value, those associated value in the indicator buffer is
99 /// [`crate::sys::NULL_DATA`] is undefined.
100 ///
101 /// This method is useful for writing performant bindings to datastructures with similar binary
102 /// layout, as it allows for using memcopy rather than iterating over individual values.
103 ///
104 /// # Example
105 ///
106 /// ```
107 /// use odbc_api::{buffers::NullableSlice, sys::NULL_DATA};
108 ///
109 /// // Memcopy the values out of the buffer, and make a mask of bools indicating the NULL
110 /// // values.
111 /// fn copy_values_and_make_mask(odbc_slice: NullableSlice<i32>) -> (Vec<i32>, Vec<bool>) {
112 /// let (values, indicators) = odbc_slice.raw_values();
113 /// let values = values.to_vec();
114 /// // Create array of bools indicating null values.
115 /// let mask: Vec<bool> = indicators
116 /// .iter()
117 /// .map(|&indicator| indicator != NULL_DATA)
118 /// .collect();
119 /// (values, mask)
120 /// }
121 /// ```
122 pub fn raw_values(&self) -> (&'a [T], &'a [isize]) {
123 (self.values, self.indicators)
124 }
125}
126
127impl<'a, T> Iterator for NullableSlice<'a, T> {
128 type Item = Option<&'a T>;
129
130 fn next(&mut self) -> Option<Self::Item> {
131 if let Some(&ind) = self.indicators.first() {
132 let item = if ind == NULL_DATA {
133 None
134 } else {
135 Some(&self.values[0])
136 };
137 self.indicators = &self.indicators[1..];
138 self.values = &self.values[1..];
139 Some(item)
140 } else {
141 None
142 }
143 }
144}
145
146unsafe impl<T> CData for ColumnWithIndicator<T>
147where
148 T: Pod,
149{
150 fn cdata_type(&self) -> odbc_sys::CDataType {
151 T::C_DATA_TYPE
152 }
153
154 fn indicator_ptr(&self) -> *const isize {
155 self.indicators.as_ptr()
156 }
157
158 fn value_ptr(&self) -> *const c_void {
159 self.values.as_ptr() as *const c_void
160 }
161
162 fn buffer_length(&self) -> isize {
163 size_of::<T>().try_into().unwrap()
164 }
165}
166
167unsafe impl<T> CDataMut for ColumnWithIndicator<T>
168where
169 T: Pod,
170{
171 fn mut_indicator_ptr(&mut self) -> *mut isize {
172 self.indicators.as_mut_ptr()
173 }
174
175 fn mut_value_ptr(&mut self) -> *mut c_void {
176 self.values.as_mut_ptr() as *mut c_void
177 }
178}
179
180unsafe impl<T> CData for Vec<T>
181where
182 T: Pod,
183{
184 fn cdata_type(&self) -> odbc_sys::CDataType {
185 T::C_DATA_TYPE
186 }
187
188 fn indicator_ptr(&self) -> *const isize {
189 null()
190 }
191
192 fn value_ptr(&self) -> *const c_void {
193 self.as_ptr() as *const c_void
194 }
195
196 fn buffer_length(&self) -> isize {
197 size_of::<T>().try_into().unwrap()
198 }
199}
200
201unsafe impl<T> CDataMut for Vec<T>
202where
203 T: Pod,
204{
205 fn mut_indicator_ptr(&mut self) -> *mut isize {
206 null_mut()
207 }
208
209 fn mut_value_ptr(&mut self) -> *mut c_void {
210 self.as_mut_ptr() as *mut c_void
211 }
212}
213
214/// Used to fill a column buffer with an iterator. Returned by
215/// [`crate::ColumnarBulkInserter::column_mut`] as part of an [`crate::buffers::AnySliceMut`].
216#[derive(Debug)]
217pub struct NullableSliceMut<'a, T> {
218 indicators: &'a mut [isize],
219 values: &'a mut [T],
220}
221
222impl<T> NullableSliceMut<'_, T> {
223 /// `true` if the slice has a length of `0`.
224 pub fn is_empty(&self) -> bool {
225 self.values.is_empty()
226 }
227
228 /// Number of entries in this slice of the buffer
229 pub fn len(&self) -> usize {
230 self.values.len()
231 }
232
233 /// Sets the value at the specified index. Use `None` to specify a `NULL` value.
234 pub fn set_cell(&mut self, index: usize, cell: Option<T>) {
235 if let Some(value) = cell {
236 self.indicators[index] = 0;
237 self.values[index] = value;
238 } else {
239 self.indicators[index] = NULL_DATA;
240 }
241 }
242
243 /// Write access to the underlying raw value and indicator buffer.
244 ///
245 /// The number of elements in the buffer is equal to `len`.
246 ///
247 /// This method is useful for writing performant bindings to datastructures with similar binary
248 /// layout, as it allows for using memcopy rather than iterating over individual values.
249 ///
250 /// # Example
251 ///
252 /// ```
253 /// use odbc_api::{buffers::NullableSliceMut, sys::NULL_DATA};
254 ///
255 /// // Memcopy the values into the buffer, and set indicators according to mask
256 /// // values.
257 /// fn copy_values_and_make_mask(
258 /// new_values: &[i32],
259 /// mask: &[bool],
260 /// odbc_slice: &mut NullableSliceMut<i32>)
261 /// {
262 /// let (values, indicators) = odbc_slice.raw_values();
263 /// values.copy_from_slice(new_values);
264 /// // Create array of bools indicating null values.
265 /// indicators.iter_mut().zip(mask.iter()).for_each(|(indicator, &mask)| {
266 /// *indicator = if mask {
267 /// 0
268 /// } else {
269 /// NULL_DATA
270 /// }
271 /// });
272 /// }
273 /// ```
274 pub fn raw_values(&mut self) -> (&mut [T], &mut [isize]) {
275 (self.values, self.indicators)
276 }
277}
278
279impl<T> NullableSliceMut<'_, T> {
280 /// Writes the elements returned by the iterator into the buffer, starting at the beginning.
281 /// Writes elements until the iterator returns `None` or the buffer can not hold more elements.
282 pub fn write(&mut self, it: impl Iterator<Item = Option<T>>) {
283 for (index, item) in it.enumerate().take(self.values.len()) {
284 self.set_cell(index, item)
285 }
286 }
287}