pub enum Indicator {
Null,
NoTotal,
Length(usize),
}Expand description
Indicates existence and length of a value.
Variants§
Null
Field does not exist
NoTotal
Field exists, but its length had not be reported by the driver.
Length(usize)
Fields exists. Value indicates number of bytes required to store the value. In case of truncated data, this is the true length of the data, before truncation occurred.
Implementations§
source§impl Indicator
impl Indicator
sourcepub fn from_isize(indicator: isize) -> Self
pub fn from_isize(indicator: isize) -> Self
Creates an indicator from an isize indicator value returned by ODBC. Users of this crate
have likely no need to call this method.
Examples found in repository?
More examples
src/buffers/bin_column.rs (line 86)
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
pub fn indicator_at(&self, row_index: usize) -> Indicator {
Indicator::from_isize(self.indicators[row_index])
}
/// Length of value at the specified position. This is different from an indicator as it refers
/// to the length of the value in the buffer, not to the length of the value in the datasource.
/// The two things are different for truncated values.
pub fn content_length_at(&self, row_index: usize) -> Option<usize> {
match self.indicator_at(row_index) {
Indicator::Null => None,
// Seen no total in the wild then binding shorter buffer to fixed sized CHAR in MSSQL.
Indicator::NoTotal => Some(self.max_len),
Indicator::Length(length) => {
let length = min(self.max_len, length);
Some(length)
}
}
}
/// Changes the maximum element length the buffer can hold. This operation is useful if you find
/// an unexpected large input during insertion. All values in the buffer will be set to NULL.
///
/// # Parameters
///
/// * `new_max_len`: New maximum string length without terminating zero.
pub fn set_max_len(&mut self, new_max_len: usize) {
let batch_size = self.indicators.len();
// Allocate a new buffer large enough to hold a batch of strings with maximum length.
let new_values = vec![0u8; new_max_len * batch_size];
// Set all indicators to NULL
self.fill_null(0, batch_size);
self.values = new_values;
self.max_len = new_max_len;
}
/// Maximum length of elements in bytes.
pub fn max_len(&self) -> usize {
self.max_len
}
/// View of the first `num_rows` values of a binary column.
///
/// Num rows may not exceed the actually amount of valid num_rows filled be the ODBC API. 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 fn view(&self, num_rows: usize) -> BinColumnView<'_> {
BinColumnView {
num_rows,
col: self,
}
}
/// Sets the value of the buffer at index to NULL or the specified bytes. This method will panic
/// on out of bounds index, or if input holds a value which is longer than the maximum allowed
/// element length.
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;
}
}
/// Fills the column with NULL, between From and To
pub fn fill_null(&mut self, from: usize, to: usize) {
for index in from..to {
self.indicators[index] = NULL_DATA;
}
}
/// Changes the maximum number of bytes per row the buffer can hold. This operation is useful if
/// you find an unexpected large input during insertion.
///
/// This is however costly, as not only does the new buffer have to be allocated, but all values
/// have to copied from the old to the new buffer.
///
/// This method could also be used to reduce the maximum length, which would truncate values in
/// the process.
///
/// This method does not adjust indicator buffers as these might hold values larger than the
/// maximum length.
///
/// # Parameters
///
/// * `new_max_len`: New maximum element length in bytes.
/// * `num_rows`: Number of valid rows currently stored in this buffer.
pub fn resize_max_element_length(&mut self, new_max_len: usize, num_rows: usize) {
debug!(
"Rebinding binary column buffer with {} elements. Maximum length {} => {}",
num_rows, self.max_len, new_max_len
);
let batch_size = self.indicators.len();
// Allocate a new buffer large enough to hold a batch of elements with maximum length.
let mut new_values = vec![0; new_max_len * batch_size];
// Copy values from old to new buffer.
let max_copy_length = min(self.max_len, new_max_len);
for ((&indicator, old_value), new_value) in self
.indicators
.iter()
.zip(self.values.chunks_exact_mut(self.max_len))
.zip(new_values.chunks_exact_mut(new_max_len))
.take(num_rows)
{
match Indicator::from_isize(indicator) {
Indicator::Null => (),
Indicator::NoTotal => {
// There is no good choice here in case we are expanding the buffer. Since
// NO_TOTAL indicates that we use the entire buffer, but in truth it would now
// be padded with 0. I currently cannot think of any use case there it would
// matter.
new_value[..max_copy_length].clone_from_slice(&old_value[..max_copy_length]);
}
Indicator::Length(num_bytes_len) => {
let num_bytes_to_copy = min(num_bytes_len, max_copy_length);
new_value[..num_bytes_to_copy].copy_from_slice(&old_value[..num_bytes_to_copy]);
}
}
}
self.values = new_values;
self.max_len = new_max_len;
}src/buffers/text_column.rs (line 119)
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
pub fn indicator_at(&self, row_index: usize) -> Indicator {
Indicator::from_isize(self.indicators[row_index])
}
/// Length of value at the specified position. This is different from an indicator as it refers
/// to the length of the value in the buffer, not to the length of the value in the datasource.
/// The two things are different for truncated values.
pub fn content_length_at(&self, row_index: usize) -> Option<usize> {
match self.indicator_at(row_index) {
Indicator::Null => None,
// Seen no total in the wild then binding shorter buffer to fixed sized CHAR in MSSQL.
Indicator::NoTotal => Some(self.max_str_len),
Indicator::Length(length_in_bytes) => {
let length_in_chars = length_in_bytes / size_of::<C>();
let length = min(self.max_str_len, length_in_chars);
Some(length)
}
}
}
/// Changes the maximum string length the buffer can hold. This operation is useful if you find
/// an unexpected large input string during insertion.
///
/// This is however costly, as not only does the new buffer have to be allocated, but all values
/// have to copied from the old to the new buffer.
///
/// This method could also be used to reduce the maximum string length, which would truncate
/// strings in the process.
///
/// This method does not adjust indicator buffers as these might hold values larger than the
/// maximum string length.
///
/// # Parameters
///
/// * `new_max_str_len`: New maximum string length without terminating zero.
/// * `num_rows`: Number of valid rows currently stored in this buffer.
pub fn resize_max_str(&mut self, new_max_str_len: usize, num_rows: usize)
where
C: Default + Copy,
{
debug!(
"Rebinding text column buffer with {} elements. Maximum string length {} => {}",
num_rows, self.max_str_len, new_max_str_len
);
let batch_size = self.indicators.len();
// Allocate a new buffer large enough to hold a batch of strings with maximum length.
let mut new_values = vec![C::default(); (new_max_str_len + 1) * batch_size];
// Copy values from old to new buffer.
let max_copy_length = min(self.max_str_len, new_max_str_len);
for ((&indicator, old_value), new_value) in self
.indicators
.iter()
.zip(self.values.chunks_exact_mut(self.max_str_len + 1))
.zip(new_values.chunks_exact_mut(new_max_str_len + 1))
.take(num_rows)
{
match Indicator::from_isize(indicator) {
Indicator::Null => (),
Indicator::NoTotal => {
// There is no good choice here in case we are expanding the buffer. Since
// NO_TOTAL indicates that we use the entire buffer, but in truth it would now
// be padded with 0. I currently cannot think of any use case there it would
// matter.
new_value[..max_copy_length].clone_from_slice(&old_value[..max_copy_length]);
}
Indicator::Length(num_bytes_len) => {
let num_bytes_to_copy = min(num_bytes_len / size_of::<C>(), max_copy_length);
new_value[..num_bytes_to_copy].copy_from_slice(&old_value[..num_bytes_to_copy]);
}
}
}
self.values = new_values;
self.max_str_len = new_max_str_len;
}sourcepub fn to_isize(self) -> isize
pub fn to_isize(self) -> isize
Creates an indicator value as required by the ODBC C API.
Examples found in repository?
More examples
src/parameter/varchar.rs (line 91)
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
pub fn from_buffer(buffer: B, indicator: Indicator) -> Self {
let buf = buffer.borrow();
match indicator {
Indicator::Null => (),
Indicator::NoTotal => {
if buf.is_empty() || *buf.last().unwrap() != 0 {
panic!("Truncated value must be terminated with zero.")
}
}
Indicator::Length(len) => {
if len > buf.len() && (buf.is_empty() || *buf.last().unwrap() != 0) {
panic!("Truncated value must be terminated with zero.")
}
}
};
Self {
buffer,
indicator: indicator.to_isize(),
}
}