pub struct ColumnarBulkInserter<S, C> { /* private fields */ }
Expand description
Can be used to execute a statement with bulk array paramters. Contrary to its name any statement
with parameters can be executed, not only INSERT
however inserting large amounts of data in
batches is the primary intended use case.
Binding new buffers is quite expensive in ODBC, so the parameter buffers are reused for each batch (so the pointers bound to the statment stay valid). So we copy each batch of data into the buffers already bound first rather than binding user defined buffer. Often the data might need to be transformed anyway, so the copy is no actual overhead. Once the buffers are filled with a batch, we send the data.
Implementations§
Source§impl<S, C> ColumnarBulkInserter<S, C>where
S: AsStatementRef,
impl<S, C> ColumnarBulkInserter<S, C>where
S: AsStatementRef,
Sourcepub unsafe fn new(
statement: S,
parameters: Vec<C>,
mapping: impl InputParameterMapping,
) -> Result<Self, Error>where
C: ColumnBuffer + HasDataType,
pub unsafe fn new(
statement: S,
parameters: Vec<C>,
mapping: impl InputParameterMapping,
) -> Result<Self, Error>where
C: ColumnBuffer + HasDataType,
Users are not encouraged to call this directly.
§Safety
- Statement is expected to be a perpared statement.
- Parameters must all be valid for insertion. An example for an invalid parameter would be a text buffer with a cell those indiactor value exceeds the maximum element length. This can happen after when truncation occurs then writing into a buffer.
Sourcepub fn execute(&mut self) -> Result<Option<CursorImpl<StatementRef<'_>>>, Error>
pub fn execute(&mut self) -> Result<Option<CursorImpl<StatementRef<'_>>>, Error>
Execute the prepared statement, with the parameters bound
Sourcepub fn set_num_rows(&mut self, num_rows: usize)
pub fn set_num_rows(&mut self, num_rows: usize)
Set number of valid rows in the buffer. Must not be larger than the batch size. If the specified number than the number of valid rows currently held by the buffer additional they will just hold the value previously assigned to them. Therfore if extending the number of valid rows users should take care to assign values to these rows. However, even if not assigend it is always guaranteed that every cell is valid for insertion and will not cause out of bounds access down in the ODBC driver. Therefore this method is safe. You can set the number of valid rows before or after filling values into the buffer, but you must do so before executing the query.
Sourcepub fn column_mut<'a>(&'a mut self, buffer_index: usize) -> C::SliceMutwhere
C: BoundInputSlice<'a>,
pub fn column_mut<'a>(&'a mut self, buffer_index: usize) -> C::SliceMutwhere
C: BoundInputSlice<'a>,
Use this method to gain write access to the actual column data.
§Parameters
buffer_index
: Please note that the buffer index is not identical to the ODBC column index. For one 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 isbuffer_index = column_index - 1
.
§Example
This method is intended to be called if using ColumnarBulkInserter
for column wise bulk
inserts.
use odbc_api::{Connection, Error, buffers::BufferDesc};
fn insert_birth_years(conn: &Connection, names: &[&str], years: &[i16])
-> Result<(), Error>
{
// All columns must have equal length.
assert_eq!(names.len(), years.len());
// Prepare the insert statement
let prepared = conn.prepare("INSERT INTO Birthdays (name, year) VALUES (?, ?)")?;
// Create a columnar buffer which fits the input parameters.
let buffer_description = [
BufferDesc::Text { max_str_len: 255 },
BufferDesc::I16 { nullable: false },
];
// Here we do everything in one batch. So the capacity is the number of input
// parameters.
let capacity = names.len();
let mut prebound = prepared.into_column_inserter(capacity, buffer_description)?;
// Set number of input rows in the current batch.
prebound.set_num_rows(names.len());
// Fill the buffer with values column by column
// Fill names
let mut col = prebound
.column_mut(0)
.as_text_view()
.expect("We know the name column to hold text.");
for (index, name) in names.iter().map(|s| Some(s.as_bytes())).enumerate() {
col.set_cell(index, name);
}
// Fill birth years
let mut col = prebound
.column_mut(1)
.as_slice::<i16>()
.expect("We know the year column to hold i16.");
col.copy_from_slice(years);
// Execute the prepared statment with the bound array parameters. Sending the values to
// the database.
prebound.execute()?;
Ok(())
}
Sourcepub fn resize(
self,
new_capacity: usize,
mapping: impl InputParameterMapping,
) -> Result<Self, Error>
pub fn resize( self, new_capacity: usize, mapping: impl InputParameterMapping, ) -> Result<Self, Error>
Resize the buffers to the new capacity. It would be hard to maintain the invariants in case of an error, so this is why this method is destroying self in case something goes wrong.
Valid rows in the buffer will be preserved. If the new capacity is smaller than the the parameter set size (the number of valid rows in the buffer), then these values will be dropped.
You may want to make use of this method in case your program flow reads from a data source with varying batch sizes and you want to insert each batch in one roundtrip. If you do not know the maximum batch size in advance, you may need to resize the buffers on the fly.
§Parameters
new_capacity
: The new capacity of the buffers. Must be at least1
. May be smaller or larger than the current capacity.mapping
: The mapping of the input parameters to the column buffers. This should be equal to the mapping used to create theColumnarBulkInserter
in the first place. If a mapping has not been specified, explicitly you can use theInOrder
mapping.
Source§impl<S> ColumnarBulkInserter<S, TextColumn<u8>>
impl<S> ColumnarBulkInserter<S, TextColumn<u8>>
Sourcepub fn append<'b>(
&mut self,
row: impl Iterator<Item = Option<&'b [u8]>>,
) -> Result<(), Error>where
S: AsStatementRef,
pub fn append<'b>(
&mut self,
row: impl Iterator<Item = Option<&'b [u8]>>,
) -> Result<(), Error>where
S: AsStatementRef,
Takes one element from the iterator for each internal column buffer and appends it to the
end of the buffer. Should a cell of the row be too large for the associated column buffer,
the column buffer will be reallocated with 1.2
times its size, and rebound to the
statement.
This method panics if it is tried to insert elements beyond batch size. It will also panic if row does not contain at least one item for each internal column buffer.