use core::ffi::{CStr, c_int};
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut, Range};
use core::ptr::NonNull;
use crate::ffi;
use crate::ty::Type;
use crate::utils::{c_to_error_text, c_to_text};
use crate::{
Bind, BindValue, Code, Error, FromColumn, FromUnsizedColumn, NotThreadSafe, Result, Row, Text,
ValueType,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct Null;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum State {
Row,
Done,
}
impl State {
#[inline]
pub fn is_done(&self) -> bool {
matches!(self, State::Done)
}
#[inline]
pub fn is_row(&self) -> bool {
matches!(self, State::Row)
}
}
pub struct Statement {
raw: NonNull<ffi::sqlite3_stmt>,
is_thread_safe: bool,
}
impl fmt::Debug for Statement {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Statement")
.field("is_thread_safe", &self.is_thread_safe)
.finish_non_exhaustive()
}
}
impl Statement {
#[inline]
pub(crate) fn from_raw(raw: NonNull<ffi::sqlite3_stmt>, is_thread_safe: bool) -> Statement {
Statement {
raw,
is_thread_safe,
}
}
#[inline]
pub(super) fn as_ptr(&self) -> *mut ffi::sqlite3_stmt {
self.raw.as_ptr()
}
#[inline]
pub(super) fn as_ptr_mut(&mut self) -> *mut ffi::sqlite3_stmt {
self.raw.as_ptr()
}
#[inline]
pub(crate) fn error_message(&self) -> &Text {
unsafe {
let db = ffi::sqlite3_db_handle(self.as_ptr());
let msg_ptr = ffi::sqlite3_errmsg(db);
c_to_error_text(msg_ptr)
}
}
pub unsafe fn into_send(self) -> Result<SendStatement, NotThreadSafe> {
if !self.is_thread_safe {
return Err(NotThreadSafe::statement());
}
Ok(SendStatement { inner: self })
}
#[inline]
pub fn next<'stmt, T>(&'stmt mut self) -> Result<Option<T>>
where
T: Row<'stmt>,
{
match self.step()? {
State::Row => Ok(Some(T::from_row(self)?)),
State::Done => Ok(None),
}
}
#[inline]
pub fn step(&mut self) -> Result<State> {
unsafe {
match ffi::sqlite3_step(self.raw.as_ptr()) {
ffi::SQLITE_ROW => Ok(State::Row),
ffi::SQLITE_DONE => Ok(State::Done),
code => Err(Error::new(Code::new(code), self.error_message())),
}
}
}
pub fn execute(&mut self, bind: impl Bind) -> Result<()> {
self.bind(bind)?;
while !self.step()?.is_done() {}
Ok(())
}
pub fn iter<T>(&mut self) -> Iter<'_, T>
where
for<'stmt> T: Row<'stmt>,
{
Iter {
stmt: self,
_marker: PhantomData,
}
}
pub fn into_iter<T>(self) -> IntoIter<T>
where
for<'stmt> T: Row<'stmt>,
{
IntoIter {
stmt: self,
_marker: PhantomData,
}
}
#[inline]
pub fn reset(&mut self) -> Result<()> {
unsafe { ffi::sqlite3_reset(self.raw.as_ptr()) };
Ok(())
}
#[inline]
pub fn clear_bindings(&mut self) -> Result<()> {
unsafe { ffi::sqlite3_clear_bindings(self.raw.as_ptr()) };
Ok(())
}
#[inline]
pub fn bind(&mut self, value: impl Bind) -> Result<()> {
self.reset()?;
value.bind(self)
}
#[inline]
pub fn bind_value(&mut self, index: c_int, value: impl BindValue) -> Result<()> {
value.bind_value(self, index)
}
#[inline]
pub fn bind_parameter_index(&self, parameter: impl AsRef<CStr>) -> Option<c_int> {
let index = unsafe {
ffi::sqlite3_bind_parameter_index(self.raw.as_ptr(), parameter.as_ref().as_ptr())
};
match index {
0 => None,
_ => Some(index),
}
}
#[inline]
pub fn column_count(&self) -> c_int {
unsafe { ffi::sqlite3_column_count(self.raw.as_ptr()) }
}
#[inline]
pub fn column_name(&self, index: c_int) -> Option<&Text> {
unsafe { c_to_text(ffi::sqlite3_column_name(self.raw.as_ptr(), index)) }
}
#[inline]
pub fn columns(&self) -> Columns {
Columns {
range: 0..self.column_count().max(0),
}
}
#[inline]
pub fn column_names(&self) -> ColumnNames<'_> {
ColumnNames {
stmt: self,
range: 0..self.column_count().max(0),
}
}
#[inline]
pub fn column_type(&self, index: c_int) -> ValueType {
unsafe { ValueType::new(ffi::sqlite3_column_type(self.raw.as_ptr(), index)) }
}
#[inline]
pub fn bind_parameter_name(&self, index: c_int) -> Option<&Text> {
unsafe { c_to_text(ffi::sqlite3_bind_parameter_name(self.raw.as_ptr(), index)) }
}
#[inline]
pub fn row<'stmt, T>(&'stmt mut self) -> Result<T>
where
T: Row<'stmt>,
{
Row::from_row(self)
}
#[inline]
pub fn column<'stmt, T>(&'stmt mut self, index: c_int) -> Result<T>
where
T: FromColumn<'stmt>,
{
let prepare = T::Type::check(self, index)?;
T::from_column(self, prepare)
}
#[inline]
pub fn unsized_column<T>(&mut self, index: c_int) -> Result<&T>
where
T: ?Sized + FromUnsizedColumn,
{
let index = T::Type::check(self, index)?;
T::from_unsized_column(self, index)
}
}
impl Drop for Statement {
#[inline]
fn drop(&mut self) {
unsafe { ffi::sqlite3_finalize(self.raw.as_ptr()) };
}
}
pub struct Iter<'stmt, T> {
stmt: &'stmt mut Statement,
_marker: PhantomData<T>,
}
impl<T> Iterator for Iter<'_, T>
where
for<'stmt> T: Row<'stmt>,
{
type Item = Result<T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.stmt.step() {
Ok(State::Row) => Some(T::from_row(self.stmt)),
Ok(State::Done) => None,
Err(e) => Some(Err(e)),
}
}
}
pub struct IntoIter<T> {
stmt: Statement,
_marker: PhantomData<T>,
}
impl<T> Iterator for IntoIter<T>
where
for<'stmt> T: Row<'stmt>,
{
type Item = Result<T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.stmt.step() {
Ok(State::Row) => Some(T::from_row(&mut self.stmt)),
Ok(State::Done) => None,
Err(e) => Some(Err(e)),
}
}
}
pub struct ColumnNames<'a> {
stmt: &'a Statement,
range: Range<c_int>,
}
impl<'a> Iterator for ColumnNames<'a> {
type Item = &'a Text;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.stmt.column_name(self.range.next()?)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.stmt.column_name(self.range.nth(n)?)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl<'a> DoubleEndedIterator for ColumnNames<'a> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.stmt.column_name(self.range.next_back()?)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.stmt.column_name(self.range.nth_back(n)?)
}
}
impl ExactSizeIterator for ColumnNames<'_> {
#[inline]
fn len(&self) -> usize {
self.range.len()
}
}
pub struct Columns {
range: Range<c_int>,
}
impl Iterator for Columns {
type Item = c_int;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.range.next()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.range.nth(n)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl DoubleEndedIterator for Columns {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.range.next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.range.nth_back(n)
}
}
pub struct SendStatement {
inner: Statement,
}
unsafe impl Send for SendStatement {}
impl Deref for SendStatement {
type Target = Statement;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for SendStatement {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl fmt::Debug for SendStatement {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}