use std::{mem::MaybeUninit, ptr, thread::panicking};
use crate::{
handles::{AsStatementRef, Statement as _},
Error,
};
use super::{error_handling_for_fetch, unbind_buffer_from_cursor, Cursor, RowSetBuffer};
pub struct BlockCursor<C: AsStatementRef, B> {
buffer: B,
cursor: C,
}
impl<C, B> BlockCursor<C, B>
where
C: Cursor,
{
pub(crate) fn new(buffer: B, cursor: C) -> Self {
Self { buffer, cursor }
}
pub fn fetch(&mut self) -> Result<Option<&B>, Error>
where
B: RowSetBuffer,
{
self.fetch_with_truncation_check(false)
}
pub fn fetch_with_truncation_check(
&mut self,
error_for_truncation: bool,
) -> Result<Option<&B>, Error>
where
B: RowSetBuffer,
{
let mut stmt = self.cursor.as_stmt_ref();
unsafe {
let result = stmt.fetch();
let has_row =
error_handling_for_fetch(result, stmt, &self.buffer, error_for_truncation)?;
Ok(has_row.then_some(&self.buffer))
}
}
pub fn unbind(self) -> Result<(C, B), Error> {
let dont_drop_me = MaybeUninit::new(self);
let self_ptr = dont_drop_me.as_ptr();
let mut cursor = unsafe { ptr::read(&(*self_ptr).cursor) };
let buffer = unsafe { ptr::read(&(*self_ptr).buffer) };
unbind_buffer_from_cursor(&mut cursor)?;
Ok((cursor, buffer))
}
}
impl<C, B> BlockCursor<C, B>
where
B: RowSetBuffer,
C: AsStatementRef,
{
pub fn row_array_size(&self) -> usize {
self.buffer.row_array_size()
}
}
impl<C, B> Drop for BlockCursor<C, B>
where
C: AsStatementRef,
{
fn drop(&mut self) {
if let Err(e) = unbind_buffer_from_cursor(&mut self.cursor) {
if !panicking() {
panic!("Unexpected error unbinding columns: {e:?}")
}
}
}
}