use crate::engine::objects::SqlTuple;
use super::super::objects::Table;
use super::super::transactions::{
TransactionId, TransactionManager, TransactionManagerError, TransactionStatus,
};
use super::{
row_formats::{ItemPointer, RowData},
RowManager, RowManagerError,
};
use async_stream::try_stream;
use futures::stream::Stream;
use std::sync::Arc;
use thiserror::Error;
#[derive(Clone)]
pub struct VisibleRowManager {
row_manager: RowManager,
tran_manager: TransactionManager,
}
impl VisibleRowManager {
pub fn new(row_manager: RowManager, tran_manager: TransactionManager) -> VisibleRowManager {
VisibleRowManager {
row_manager,
tran_manager,
}
}
pub async fn insert_row(
&self,
current_tran_id: TransactionId,
table: &Arc<Table>,
user_data: SqlTuple,
) -> Result<ItemPointer, VisibleRowManagerError> {
self.row_manager
.insert_row(current_tran_id, table, user_data)
.await
.map_err(VisibleRowManagerError::RowManagerError)
}
pub async fn get(
&mut self,
tran_id: TransactionId,
table: &Arc<Table>,
row_pointer: ItemPointer,
) -> Result<RowData, VisibleRowManagerError> {
let row = self.row_manager.get(table, row_pointer).await?;
if VisibleRowManager::is_visible(&mut self.tran_manager, tran_id, &row).await? {
Ok(row)
} else {
Err(VisibleRowManagerError::NotVisibleRow(row))
}
}
pub fn get_stream(
&self,
tran_id: TransactionId,
table: &Arc<Table>,
) -> impl Stream<Item = Result<RowData, VisibleRowManagerError>> {
let rm = self.row_manager.clone();
let mut tm = self.tran_manager.clone();
let table = table.clone();
try_stream! {
for await row in rm.get_stream(&table) {
let unwrap_row = row?;
if VisibleRowManager::is_visible(&mut tm, tran_id, &unwrap_row).await? {
yield unwrap_row;
}
}
}
}
pub async fn any_visible(
&mut self,
table: &Arc<Table>,
tran_id: TransactionId,
ptrs: &Vec<ItemPointer>,
) -> Result<bool, VisibleRowManagerError> {
for p in ptrs {
match self.get(tran_id, table, *p).await {
Ok(o) => return Ok(true),
Err(VisibleRowManagerError::NotVisibleRow(_)) => continue,
Err(e) => {
return Err(e);
}
}
}
return Ok(false);
}
async fn is_visible(
tm: &mut TransactionManager,
tran_id: TransactionId,
row_data: &RowData,
) -> Result<bool, VisibleRowManagerError> {
if row_data.min == tran_id {
match row_data.max {
Some(m) => {
if m == tran_id {
return Ok(false);
} else {
return Ok(true);
}
}
None => return Ok(true),
}
}
if row_data.min > tran_id {
return Ok(false);
}
if tm.get_status(row_data.min).await? != TransactionStatus::Commited {
return Ok(false);
}
match row_data.max {
Some(m) => {
if m > tran_id || tm.get_status(m).await? != TransactionStatus::Commited {
Ok(true)
} else {
Ok(false)
}
}
None => Ok(true),
}
}
}
#[derive(Error, Debug)]
pub enum VisibleRowManagerError {
#[error("Row {0} is not visible")]
NotVisibleRow(RowData),
#[error("Test")]
Test(),
#[error(transparent)]
RowManagerError(#[from] RowManagerError),
#[error(transparent)]
TransactionManagerError(#[from] TransactionManagerError),
}