Skip to content

Commit

Permalink
rebind columns
Browse files Browse the repository at this point in the history
  • Loading branch information
pacman82 committed Feb 1, 2021
1 parent b258c69 commit 21f1a45
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 36 deletions.
19 changes: 18 additions & 1 deletion odbc-api/src/buffers/bin_column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,29 @@ pub struct BinColumnWriter<'a> {

impl<'a> BinColumnWriter<'a> {
/// Fill the binary column with values by consuming the iterator and copying its items into the
/// buffer. It will not extract more items from the iterator than the buffer may hold.
/// buffer. It will not extract more items from the iterator than the buffer may hold. Should
/// some elements be longer than the maximum element length a rebind is triggered and the buffer
/// is reallocated to make room for the longer elements.
pub fn write<'b>(&mut self, it: impl Iterator<Item = Option<&'b [u8]>>) {
for (index, item) in it.enumerate().take(self.to) {
if let Some(item) = item {
if item.len() > self.column.max_len {
self.rebind((item.len() as f64 * 1.2) as usize)
}
}
self.column.set_value(index, item)
}
}

/// Use this method to change the maximum element length.
///
/// # Parameters
///
/// * `new_max_len`: New maximum length of values in the column. Existing values are truncated.
///
pub fn rebind(&mut self, new_max_len: usize) {
self.column.rebind(new_max_len, self.to)
}
}

unsafe impl CData for BinColumn {
Expand Down
23 changes: 0 additions & 23 deletions odbc-api/src/buffers/columnar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,29 +592,6 @@ impl ColumnarRowSet {
*self.num_rows
}

/// Use this method to change the maximum element length of a variable sized column. This method
/// panics if buffer index is not a variable sized text or binary buffer.
///
/// # Parameters
///
/// * `buffer_index`: Please note that the buffer index is not identical to the ODBC column
/// index. For once it is zero based. It also indexes the buffer bound, and not the columns of
/// the output result set. This is important, because not every column needs to be bound. Some
/// columns may simply be ignored. That being said, if every column of the output is bound in
/// the buffer, in the same order in which they are enumerated in the result set, the
/// relationship between column index and buffer index is `buffer_index = column_index - 1`.
/// * `new_max_len`: New maximum length of values in the column. Existing values are truncated.
/// The length is exculding the terminating zero if a text buffer is specified.
///
pub fn rebind(&mut self, buffer_index: usize, new_max_len: usize) {
let (_col_indext, ref mut buffer) = self.columns[buffer_index];
match buffer {
AnyColumnBuffer::Binary(buf) => buf.rebind(new_max_len, *self.num_rows),
AnyColumnBuffer::Text(_) => {}
_ => panic!("Rebind must be called on a column type with variable length."),
}
}

/// Set number of valid rows in the buffer. May not be larger than the batch size. If the
/// specified number should be larger than the number of valid rows currently held by the buffer
/// additional rows with the default value are going to be created.
Expand Down
26 changes: 22 additions & 4 deletions odbc-api/src/buffers/text_column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl TextColumn {
/// A writer able to fill the first `n` elements of the buffer, from an iterator.
pub fn writer_n(&mut self, n: usize) -> TextColumnWriter<'_> {
TextColumnWriter {
text_column: self,
column: self,
to: n,
}
}
Expand Down Expand Up @@ -207,19 +207,37 @@ impl<'c> Iterator for TextColumnIt<'c> {
/// Fills a text column buffer with elements from an Iterator.
#[derive(Debug)]
pub struct TextColumnWriter<'a> {
text_column: &'a mut TextColumn,
column: &'a mut TextColumn,
/// Upper limit, the text column writer will not write beyond this index.
to: usize,
}

impl<'a> TextColumnWriter<'a> {
/// Fill the text column with values by consuming the iterator and copying its items into the
/// buffer. It will not extract more items from the iterator than the buffer may hold.
/// buffer. It will not extract more items from the iterator than the buffer may hold. Should
/// some elements be longer than the maximum string length a rebind is triggered and the buffer
/// is reallocated to make room for the longer elements.
pub fn write<'b>(&mut self, it: impl Iterator<Item = Option<&'b [u8]>>) {
for (index, item) in it.enumerate().take(self.to) {
self.text_column.set_value(index, item)
if let Some(item) = item {
if item.len() > self.column.max_str_len {
self.rebind((item.len() as f64 * 1.2) as usize)
}
}
self.column.set_value(index, item)
}
}

/// Use this method to change the maximum string length (excluding terminating zero).
///
/// # Parameters
///
/// * `new_max_len`: New maximum length of values in the column. Existing values are truncated.
/// The length is exculding the terminating zero.
///
pub fn rebind(&mut self, new_max_len: usize) {
self.column.rebind(new_max_len, self.to)
}
}

unsafe impl CData for TextColumn {
Expand Down
21 changes: 13 additions & 8 deletions odbc-api/tests/mssql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,22 +253,27 @@ fn columnar_fetch_binary() {
fn columnar_insert_varbinary() {
// Setup
let conn = ENV.connect_with_connection_string(MSSQL).unwrap();
setup_empty_table(&conn, "ColumnarInsertVarbinary", &["VARBINARY(10)"]).unwrap();
setup_empty_table(&conn, "ColumnarInsertVarbinary", &["VARBINARY(13)"]).unwrap();

// Fill buffer with values
let desc = BufferDescription {
kind: BufferKind::Binary { length: 5 },
nullable: true,
};
let mut buffer = ColumnarRowSet::new(10, iter::once(desc));
buffer.set_num_rows(3);

// Input values to insert. Note that the last element has > 5 chars and is going to trigger a
// reallocation of the underlying buffer.
let input = [
Some(&b"Hello"[..]),
Some(&b"World"[..]),
None,
Some(&b"Hello, World!"[..]),
];

buffer.set_num_rows(input.len());
if let AnyColumnViewMut::Binary(mut writer) = buffer.column_mut(0) {
writer.write(
[Some(&b"Hello"[..]), Some(&b"World"[..]), None]
.iter()
.copied(),
);
writer.write(input.iter().copied());
} else {
panic!("Expected binary column writer");
};
Expand All @@ -286,7 +291,7 @@ fn columnar_insert_varbinary() {
.unwrap()
.unwrap();
let actual = cursor_to_string(cursor);
let expected = "48656C6C6F\n576F726C64\nNULL";
let expected = "48656C6C6F\n576F726C64\nNULL\n48656C6C6F2C20576F726C6421";
assert_eq!(expected, actual);
}

Expand Down

0 comments on commit 21f1a45

Please sign in to comment.