use crate::{
handles::{CData, CDataMut, HasDataType},
DataType,
};
use odbc_sys::{CDataType, NULL_DATA};
use std::{cmp::min, convert::TryInto, ffi::c_void};
#[derive(Debug)]
pub struct BinColumn {
max_len: usize,
values: Vec<u8>,
indicators: Vec<isize>,
}
impl BinColumn {
pub fn new(batch_size: usize, max_len: usize) -> Self {
BinColumn {
max_len,
values: vec![0; max_len * batch_size],
indicators: vec![0; batch_size],
}
}
pub unsafe fn value_at(&self, row_index: usize) -> Option<&[u8]> {
let len = self.indicators[row_index];
if len == NULL_DATA {
None
} else {
let offset = row_index * self.max_len;
let length = min(self.max_len, len as usize);
Some(&self.values[offset..offset + length])
}
}
pub fn set_max_len(&mut self, new_max_len: usize) {
let batch_size = self.indicators.len();
let new_values = vec![0u8; new_max_len * batch_size];
self.fill_null(0, batch_size);
self.values = new_values;
self.max_len = new_max_len;
}
pub unsafe fn iter(&self, num_rows: usize) -> BinColumnIt {
BinColumnIt {
pos: 0,
num_rows,
col: &self,
}
}
pub fn set_value(&mut self, index: usize, input: Option<&[u8]>) {
if let Some(input) = input {
self.indicators[index] = input.len().try_into().unwrap();
if input.len() > self.max_len {
panic!(
"Tried to insert a value into a binary buffer which is larger than the maximum \
allowed element length for the buffer."
);
}
let start = self.max_len * index;
let end = start + input.len();
let buf = &mut self.values[start..end];
buf.copy_from_slice(input);
} else {
self.indicators[index] = NULL_DATA;
}
}
pub fn fill_null(&mut self, from: usize, to: usize) {
for index in from..to {
self.indicators[index] = NULL_DATA;
}
}
pub fn writer_n(&mut self, n: usize) -> BinColumnWriter<'_> {
BinColumnWriter {
column: self,
to: n,
}
}
}
#[derive(Debug)]
pub struct BinColumnIt<'c> {
pos: usize,
num_rows: usize,
col: &'c BinColumn,
}
impl<'c> Iterator for BinColumnIt<'c> {
type Item = Option<&'c [u8]>;
fn next(&mut self) -> Option<Self::Item> {
if self.pos == self.num_rows {
None
} else {
let ret = unsafe { Some(self.col.value_at(self.pos)) };
self.pos += 1;
ret
}
}
}
#[derive(Debug)]
pub struct BinColumnWriter<'a> {
column: &'a mut BinColumn,
to: usize,
}
impl<'a> BinColumnWriter<'a> {
pub fn write<'b>(&mut self, it: impl Iterator<Item = Option<&'b [u8]>>) {
for (index, item) in it.enumerate().take(self.to) {
self.column.set_value(index, item)
}
}
pub fn set_max_len(&mut self, new_max_len: usize) {
self.column.set_max_len(new_max_len)
}
}
unsafe impl CData for BinColumn {
fn cdata_type(&self) -> CDataType {
CDataType::Binary
}
fn indicator_ptr(&self) -> *const isize {
self.indicators.as_ptr()
}
fn value_ptr(&self) -> *const c_void {
self.values.as_ptr() as *const c_void
}
fn buffer_length(&self) -> isize {
self.max_len.try_into().unwrap()
}
}
unsafe impl HasDataType for BinColumn {
fn data_type(&self) -> DataType {
DataType::Varbinary {
length: self.max_len,
}
}
}
unsafe impl CDataMut for BinColumn {
fn mut_indicator_ptr(&mut self) -> *mut isize {
self.indicators.as_mut_ptr()
}
fn mut_value_ptr(&mut self) -> *mut c_void {
self.values.as_mut_ptr() as *mut c_void
}
}