use crate::{
handles::{CDataMut, Description, Statement},
ColumnDescription, Error,
};
use odbc_sys::SqlDataType;
use std::{
borrow::BorrowMut,
char::{decode_utf16, REPLACEMENT_CHARACTER},
convert::TryInto,
marker::PhantomData,
thread::panicking,
};
pub trait Cursor: Sized {
fn describe_col(
&self,
column_number: u16,
column_description: &mut ColumnDescription,
) -> Result<(), Error>;
fn num_result_cols(&self) -> Result<i16, Error>;
unsafe fn fetch(&mut self) -> Result<bool, Error>;
unsafe fn set_row_array_size(&mut self, size: u32) -> Result<(), Error>;
unsafe fn set_num_rows_fetched(&mut self, num_rows: &mut usize) -> Result<(), Error>;
unsafe fn set_row_bind_type(&mut self, row_size: u32) -> Result<(), Error>;
fn unbind_cols(&mut self) -> Result<(), Error>;
unsafe fn bind_col(
&mut self,
column_number: u16,
target: &mut impl CDataMut,
) -> Result<(), Error>;
fn is_unsigned_column(&self, column_number: u16) -> Result<bool, Error>;
fn bind_buffer<B>(self, row_set_buffer: B) -> Result<RowSetCursor<Self, B>, Error>
where
B: RowSetBuffer;
fn col_type(&self, column_number: u16) -> Result<SqlDataType, Error>;
fn col_concise_type(&self, column_number: u16) -> Result<SqlDataType, Error>;
fn col_octet_length(&self, column_number: u16) -> Result<isize, Error>;
fn col_display_size(&self, column_number: u16) -> Result<isize, Error>;
fn col_precision(&self, column_number: u16) -> Result<isize, Error>;
fn col_scale(&self, column_number: u16) -> Result<isize, Error>;
fn col_name(&self, column_number: u16, buf: &mut Vec<u16>) -> Result<(), Error>;
fn column_names(&self) -> Result<ColumnNamesIt<'_, Self>, Error> {
ColumnNamesIt::new(self)
}
fn application_row_descriptor(&self) -> Result<Description, Error>;
}
pub struct ColumnNamesIt<'c, C> {
cursor: &'c C,
buffer: Vec<u16>,
column: u16,
num_cols: u16,
}
impl<'c, C: Cursor> ColumnNamesIt<'c, C> {
fn new(cursor: &'c C) -> Result<Self, Error> {
Ok(Self {
cursor,
buffer: Vec::with_capacity(128),
num_cols: cursor.num_result_cols()?.try_into().unwrap(),
column: 1,
})
}
}
impl<C> Iterator for ColumnNamesIt<'_, C>
where
C: Cursor,
{
type Item = Result<String, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.column <= self.num_cols {
let result = self
.cursor
.col_name(self.column, &mut self.buffer)
.map(|()| {
decode_utf16(self.buffer.iter().copied())
.map(|decoding_result| decoding_result.unwrap_or(REPLACEMENT_CHARACTER))
.collect()
});
self.column += 1;
Some(result)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let num_cols = self.num_cols as usize;
(num_cols, Some(num_cols))
}
}
impl<C> ExactSizeIterator for ColumnNamesIt<'_, C> where C: Cursor {}
pub struct CursorImpl<'open_connection, Stmt: BorrowMut<Statement<'open_connection>>> {
statement: Stmt,
connection: PhantomData<Statement<'open_connection>>,
}
impl<'o, S> Drop for CursorImpl<'o, S>
where
S: BorrowMut<Statement<'o>>,
{
fn drop(&mut self) {
if let Err(e) = self.statement.borrow_mut().close_cursor() {
if !panicking() {
panic!("Unexpected error closing cursor: {:?}", e)
}
}
}
}
impl<'o, S> Cursor for CursorImpl<'o, S>
where
S: BorrowMut<Statement<'o>>,
{
fn describe_col(
&self,
column_number: u16,
column_description: &mut ColumnDescription,
) -> Result<(), Error> {
self.statement
.borrow()
.describe_col(column_number, column_description)?;
Ok(())
}
fn num_result_cols(&self) -> Result<i16, Error> {
self.statement.borrow().num_result_cols()
}
unsafe fn fetch(&mut self) -> Result<bool, Error> {
self.statement.borrow_mut().fetch()
}
unsafe fn set_row_array_size(&mut self, size: u32) -> Result<(), Error> {
self.statement.borrow_mut().set_row_array_size(size)
}
unsafe fn set_num_rows_fetched(&mut self, num_rows: &mut usize) -> Result<(), Error> {
self.statement.borrow_mut().set_num_rows_fetched(num_rows)
}
unsafe fn set_row_bind_type(&mut self, row_size: u32) -> Result<(), Error> {
self.statement.borrow_mut().set_row_bind_type(row_size)
}
fn unbind_cols(&mut self) -> Result<(), Error> {
self.statement.borrow_mut().unbind_cols()
}
unsafe fn bind_col(
&mut self,
column_number: u16,
target: &mut impl CDataMut,
) -> Result<(), Error> {
self.statement.borrow_mut().bind_col(column_number, target)
}
fn is_unsigned_column(&self, column_number: u16) -> Result<bool, Error> {
self.statement.borrow().is_unsigned_column(column_number)
}
fn bind_buffer<B>(mut self, mut row_set_buffer: B) -> Result<RowSetCursor<Self, B>, Error>
where
B: RowSetBuffer,
{
unsafe {
row_set_buffer.bind_to_cursor(&mut self)?;
}
Ok(RowSetCursor::new(row_set_buffer, self))
}
fn col_type(&self, column_number: u16) -> Result<SqlDataType, Error> {
self.statement.borrow().col_type(column_number)
}
fn col_concise_type(&self, column_number: u16) -> Result<SqlDataType, Error> {
self.statement.borrow().col_type(column_number)
}
fn col_octet_length(&self, column_number: u16) -> Result<isize, Error> {
self.statement.borrow().col_octet_length(column_number)
}
fn col_display_size(&self, column_number: u16) -> Result<isize, Error> {
self.statement.borrow().col_display_size(column_number)
}
fn col_precision(&self, column_number: u16) -> Result<isize, Error> {
self.statement.borrow().col_precision(column_number)
}
fn col_scale(&self, column_number: u16) -> Result<isize, Error> {
self.statement.borrow().col_scale(column_number)
}
fn col_name(&self, column_number: u16, buf: &mut Vec<u16>) -> Result<(), Error> {
self.statement.borrow().col_name(column_number, buf)
}
fn application_row_descriptor(&self) -> Result<Description, Error> {
self.statement.borrow().application_row_descriptor()
}
fn column_names(&self) -> Result<ColumnNamesIt<'_, Self>, Error> {
ColumnNamesIt::new(self)
}
}
impl<'o, S> CursorImpl<'o, S>
where
S: BorrowMut<Statement<'o>>,
{
pub(crate) fn new(statement: S) -> Self {
Self {
statement,
connection: PhantomData,
}
}
}
pub unsafe trait RowSetBuffer {
unsafe fn bind_to_cursor(&mut self, cursor: &mut impl Cursor) -> Result<(), Error>;
}
unsafe impl<T: RowSetBuffer> RowSetBuffer for &mut T {
unsafe fn bind_to_cursor(&mut self, cursor: &mut impl Cursor) -> Result<(), Error> {
(*self).bind_to_cursor(cursor)
}
}
pub struct RowSetCursor<C, B> {
buffer: B,
cursor: C,
}
impl<C, B> RowSetCursor<C, B> {
fn new(buffer: B, cursor: C) -> Self {
Self { buffer, cursor }
}
}
impl<C, B> RowSetCursor<C, B>
where
C: Cursor,
{
pub fn fetch(&mut self) -> Result<Option<&B>, Error> {
let has_data = unsafe { self.cursor.fetch()? };
if has_data {
Ok(Some(&self.buffer))
} else {
Ok(None)
}
}
pub fn unbind(mut self) -> Result<C, Error> {
self.cursor.unbind_cols()?;
Ok(self.cursor)
}
}