use std::mem::{self, MaybeUninit};
use std::ptr;
use crate::sql::data_source::DataSource;
use crate::sql::engine::{Engine, LocalEngine};
use crate::sql::stmt::{ExecutionContext, Statement};
use crate::sql::value::ToValue;
use crate::sql::{mcosql_error_code, result_from_code};
use crate::{exdb_sys, Result};
pub enum Mode {
ReadOnly = exdb_sys::mcosql_transaction_mode::TM_READ_ONLY as isize,
Update = exdb_sys::mcosql_transaction_mode::TM_UPDATE as isize,
ReadWrite = exdb_sys::mcosql_transaction_mode::TM_READ_WRITE as isize,
Exclusive = exdb_sys::mcosql_transaction_mode::TM_EXCLUSIVE as isize,
}
pub struct Transaction<'a> {
pub(crate) engine: &'a dyn Engine,
pub(crate) h: exdb_sys::transaction_t,
}
impl<'a> Transaction<'a> {
pub fn begin(engine: &'a LocalEngine, mode: Mode, priority: i32) -> Result<Transaction<'a>> {
let mut h = MaybeUninit::uninit();
result_from_code(unsafe {
exdb_sys::mcosql_begin_transaction(
engine.h,
h.as_mut_ptr(),
mode as exdb_sys::mcosql_transaction_mode::Type,
priority,
)
})
.and(Ok(Transaction {
engine,
h: unsafe { h.assume_init() },
}))
}
pub fn execute_statement(&self, sql: &str, args: &[&dyn ToValue]) -> Result<i64> {
Statement::execute_statement(ExecutionContext::with_transaction(self), sql, args)
}
pub fn execute_query(
&'a self,
sql: &str,
args: &[&dyn ToValue],
) -> Result<Option<DataSource<'a>>> {
Statement::execute_query(ExecutionContext::with_transaction(self), sql, args)
}
pub fn commit(mut self) -> Result<()> {
self.finalize(true)
}
pub fn rollback(mut self) -> Result<()> {
self.finalize(false)
}
fn finalize(&mut self, commit: bool) -> Result<()> {
result_from_code(unsafe {
let rc = if commit {
exdb_sys::mcosql_commit_transaction(self.h)
} else {
exdb_sys::mcosql_rollback_transaction(self.h)
};
let rc2 =
exdb_sys::mcosql_release_transaction(mem::replace(&mut self.h, ptr::null_mut()));
if rc != mcosql_error_code::SQL_OK {
rc
} else {
rc2
}
})
}
}
impl<'a> Drop for Transaction<'a> {
fn drop(&mut self) {
if !self.h.is_null() {
let ret = self.finalize(false);
debug_assert!(ret.is_ok());
}
}
}