pub trait Cursor: ResultSetMetadata {
// Required methods
fn bind_buffer<B>(
self,
row_set_buffer: B,
) -> Result<BlockCursor<Self, B>, Error>
where Self: Sized,
B: RowSetBuffer;
fn more_results(self) -> Result<Option<Self>, Error>
where Self: Sized;
// Provided method
fn next_row(&mut self) -> Result<Option<CursorRow<'_>>, Error> { ... }
}
Expand description
Cursors are used to process and iterate the result sets returned by executing queries.
§Example: Fetching result in batches
use odbc_api::{Cursor, buffers::{BufferDesc, ColumnarAnyBuffer}, Error};
/// Fetches all values from the first column of the cursor as i32 in batches of 100 and stores
/// them in a vector.
fn fetch_all_ints(cursor: impl Cursor) -> Result<Vec<i32>, Error> {
let mut all_ints = Vec::new();
// Batch size determines how many values we fetch at once.
let batch_size = 100;
// We expect the first column to hold INTEGERs (or a type convertible to INTEGER). Use
// the metadata on the result set, if you want to investige the types of the columns at
// runtime.
let description = BufferDesc::I32 { nullable: false };
// This is the buffer we bind to the driver, and repeatedly use to fetch each batch
let buffer = ColumnarAnyBuffer::from_descs(batch_size, [description]);
// Bind buffer to cursor
let mut row_set_buffer = cursor.bind_buffer(buffer)?;
// Fetch data batch by batch
while let Some(batch) = row_set_buffer.fetch()? {
all_ints.extend_from_slice(batch.column(0).as_slice().unwrap())
}
Ok(all_ints)
}
Required Methods§
Sourcefn bind_buffer<B>(
self,
row_set_buffer: B,
) -> Result<BlockCursor<Self, B>, Error>where
Self: Sized,
B: RowSetBuffer,
fn bind_buffer<B>(
self,
row_set_buffer: B,
) -> Result<BlockCursor<Self, B>, Error>where
Self: Sized,
B: RowSetBuffer,
Binds this cursor to a buffer holding a row set.
Sourcefn more_results(self) -> Result<Option<Self>, Error>where
Self: Sized,
fn more_results(self) -> Result<Option<Self>, Error>where
Self: Sized,
For some datasources it is possible to create more than one result set at once via a call to execute. E.g. by calling a stored procedure or executing multiple SQL statements at once. This method consumes the current cursor and creates a new one representing the next result set should it exist.
Provided Methods§
Sourcefn next_row(&mut self) -> Result<Option<CursorRow<'_>>, Error>
fn next_row(&mut self) -> Result<Option<CursorRow<'_>>, Error>
Advances the cursor to the next row in the result set. This is Slow. Bind
crate::buffers
instead, for good performance.
⚠ While this method is very convenient due to the fact that the application does not have
to declare and bind specific buffers, it is also in many situations extremely slow. Concrete
performance depends on the ODBC driver in question, but it is likely it performs a roundtrip
to the datasource for each individual row. It is also likely an extra conversion is
performed then requesting individual fields, since the C buffer type is not known to the
driver in advance. Consider binding a buffer to the cursor first using
Self::bind_buffer
.
That being said, it is a convenient programming model, as the developer does not need to
prepare and allocate the buffers beforehand. It is also a good way to retrieve really large
single values out of a data source (like one large text file). See CursorRow::get_text
.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.