1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use super::{BindColParameters, ColumnBuffer};
use odbc_sys::{CDataType, Len, Pointer, NULL_DATA};
use std::{cmp::min, convert::TryInto};

/// A buffer intended to be bound to a column of a cursor. Elements of the buffer will contain a

/// variable amount of characters up to a maximum string length. Since most SQL types have a string

/// representation this buffer can be bound to a column of almost any type, ODBC driver and driver

/// manager should take care of the conversion. Since elements of this type have variable length an

/// indicator buffer needs to be bound, wether the column is nullable or not, and therefore does not

/// matter for this buffer.

pub struct TextColumn {
    max_str_len: usize,
    values: Vec<u8>,
    indicators: Vec<Len>,
}

unsafe impl ColumnBuffer for TextColumn {
    fn bind_arguments(&mut self) -> BindColParameters {
        BindColParameters {
            target_type: CDataType::Char,
            target_value: self.values.as_mut_ptr() as Pointer,
            target_length: self.max_str_len.try_into().unwrap(),
            indicator: self.indicators.as_mut_ptr(),
        }
    }
}

impl TextColumn {
    /// This will allocate a value and indicator buffer for `batch_size` elments. Each value may

    /// have a maximum length of `max_str_len`. This implies that max_str_len is increased by one in

    /// order to make space for the null terminating zero at the end of strings.

    pub fn new(batch_size: usize, mut max_str_len: usize) -> Self {
        max_str_len += 1;
        TextColumn {
            max_str_len,
            values: vec![0; (max_str_len + 1) * batch_size],
            indicators: vec![0; batch_size],
        }
    }

    /// Return the value for the given row index.

    ///

    /// #Safety

    ///

    /// The column buffer does not know how many elements were in the last row group, and therefore

    /// can not guarantee the accessed element to be valid and in a defined state. It also can not

    /// panic on accessing an undefined element. It will panic however if `row_index` is larger or

    /// equal to the maximum number of elements in the buffer.

    pub unsafe fn value_at(&self, row_index: usize) -> Option<&[u8]> {
        let str_len = self.indicators[row_index];
        if str_len == NULL_DATA {
            None
        } else {
            let offset = row_index * self.max_str_len;
            let length = min(self.max_str_len, str_len as usize);
            Some(&self.values[offset..offset + length])
        }
    }
}