use crate::{
Engine, NontransactionalSequenceValue, SessionLastSequenceReference, SessionSequenceValue,
SessionStateSnapshot,
};
use std::collections::BTreeMap;
use uqa_core::RelationIdentity;
use uqa_execution::catalog::sequence::values::context::{
SequenceCachesWrite, SequenceSessionRead, SequenceSessionWrite, SequenceStatesWrite,
SequenceValueContext, SequenceValueOperation, SequenceValueRuntime, SequenceValueTransactions,
};
use uqa_sql::{catalog::sequence_functions::value_error::SequenceValueError, SQLError};
use uqa_storage::{PersistentStorageSession, StorageBackendResult};
struct SessionRead<'a>(parking_lot::RwLockReadGuard<'a, SessionStateSnapshot>);
struct SessionWrite<'a>(parking_lot::RwLockWriteGuard<'a, SessionStateSnapshot>);
impl SequenceSessionRead for SessionRead<'_> {
fn currvals(&self) -> &BTreeMap<RelationIdentity, SessionSequenceValue> {
&self.0.sequence_currvals
}
fn last(&self) -> Option<&SessionLastSequenceReference> {
self.0.last_sequence.as_ref()
}
}
impl SequenceSessionWrite for SessionWrite<'_> {
fn currvals_mut(&mut self) -> &mut BTreeMap<RelationIdentity, SessionSequenceValue> {
&mut self.0.sequence_currvals
}
fn last_mut(&mut self) -> &mut Option<SessionLastSequenceReference> {
&mut self.0.last_sequence
}
}
impl SequenceValueRuntime for Engine {
fn cancellation(&self) -> &uqa_core::CancellationToken {
&self.runtime.cancellation
}
fn states_write(&self) -> SequenceStatesWrite<'_> {
Box::new(self.durable.sequences.write())
}
fn caches(&self) -> SequenceCachesWrite<'_> {
Box::new(self.session.sequence_caches.lock())
}
fn session_read(&self) -> Box<dyn SequenceSessionRead + '_> {
Box::new(SessionRead(self.session.state.read()))
}
fn session_write(&self) -> Box<dyn SequenceSessionWrite + '_> {
Box::new(SessionWrite(self.session.state.write()))
}
fn current_transaction_is_read_only(&self) -> bool {
Engine::current_transaction_is_read_only(self)
}
fn open_nontransactional_sequence_session(
&self,
) -> StorageBackendResult<Option<PersistentStorageSession>> {
Engine::open_independent_catalog_session(self, Some(&self.runtime.cancellation))
}
fn prepare_explicit_transaction_writer(&self) -> Result<(), SQLError> {
self.prepare_transaction_writer().map(|_| ())
}
fn record_nontransactional_sequence_value(
&self,
definition_generation: [u8; 16],
value: NontransactionalSequenceValue,
defines_lastval: bool,
) {
Engine::record_nontransactional_sequence_value(
self,
definition_generation,
value,
defines_lastval,
);
}
}
impl SequenceValueTransactions for Engine {
fn with_value_transaction(
&self,
operation: SequenceValueOperation<'_>,
) -> Result<i64, SequenceValueError> {
if self.transaction_depth() != 0 {
self.ensure_transaction_usable()?;
operation()
} else {
self.transaction_with_error(|_| operation(), SequenceValueError::from)
}
}
fn transaction_lock_mark(&self) -> u32 {
self.session
.transactions
.lock()
.first()
.map_or(0, |frame| frame.begin_lock_mark)
}
}
impl Engine {
pub(crate) fn sequence_value_context(&self) -> SequenceValueContext<'_> {
SequenceValueContext {
locks: self,
transactions: self,
snapshots: self,
privileges: self.sequence_privilege_inquiry(),
runtime: self,
storage: self.storage.catalog.as_deref(),
}
}
fn with_sequence_value_session(
&self,
operation: impl FnOnce(SequenceValueContext<'_>) -> Result<i64, SequenceValueError>,
) -> Result<i64, String> {
let _statement = self.runtime.statement_gate.lock();
let outside_statement = self
.runtime
.sql_execution_depth
.load(std::sync::atomic::Ordering::Relaxed)
== 0
&& self.session.row_lock_statements.lock().is_empty();
if outside_statement && self.transaction_depth() != 0 {
self.ensure_transaction_usable()
.map_err(|error| error.to_string())?;
self.prepare_explicit_statement_snapshot(true)
.map_err(|error| error.to_string())?;
}
operation(self.sequence_value_context()).map_err(|error| error.to_string())
}
pub fn nextval(&self, name: &str) -> Result<i64, String> {
self.with_sequence_value_session(|values| values.nextval(name))
}
pub(crate) fn nextval_sql(&self, name: &str) -> Result<i64, SQLError> {
self.sequence_value_context()
.nextval(name)
.map_err(SequenceValueError::into_sql_error)
}
pub fn currval(&self, name: &str) -> Result<i64, String> {
self.with_sequence_value_session(|values| values.currval(name))
}
pub(crate) fn currval_sql(&self, name: &str) -> Result<i64, SQLError> {
self.sequence_value_context()
.currval(name)
.map_err(SequenceValueError::into_sql_error)
}
pub fn lastval(&self) -> Result<i64, String> {
self.with_sequence_value_session(|values| values.lastval())
}
pub(crate) fn lastval_sql(&self) -> Result<i64, SQLError> {
self.sequence_value_context()
.lastval()
.map_err(SequenceValueError::into_sql_error)
}
pub fn setval(&self, name: &str, value: i64) -> Result<i64, String> {
self.setval_with_is_called(name, value, true)
}
pub fn setval_with_is_called(
&self,
name: &str,
value: i64,
is_called: bool,
) -> Result<i64, String> {
self.with_sequence_value_session(|values| values.setval(name, value, is_called))
}
pub(crate) fn setval_sql(
&self,
name: &str,
value: i64,
is_called: bool,
) -> Result<i64, SQLError> {
self.sequence_value_context()
.setval(name, value, is_called)
.map_err(SequenceValueError::into_sql_error)
}
}