use std::fmt;
#[derive(Debug)]
pub enum AkarError {
Storage(StorageError),
Transaction(TransactionError),
Catalog(CatalogError),
Binder(BinderError),
Planner(PlannerError),
Processor(ProcessorError),
Parser(String),
Io(std::io::Error),
Internal(String),
}
impl fmt::Display for AkarError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Storage(e) => write!(f, "storage: {e}"),
Self::Transaction(e) => write!(f, "transaction: {e}"),
Self::Catalog(e) => write!(f, "catalog: {e}"),
Self::Binder(e) => write!(f, "binder: {e}"),
Self::Planner(e) => write!(f, "planner: {e}"),
Self::Processor(e) => write!(f, "processor: {e}"),
Self::Parser(s) => write!(f, "parser: {s}"),
Self::Io(e) => write!(f, "io: {e}"),
Self::Internal(s) => write!(f, "internal: {s}"),
}
}
}
impl std::error::Error for AkarError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Storage(e) => Some(e),
Self::Transaction(e) => Some(e),
Self::Catalog(e) => Some(e),
Self::Binder(e) => Some(e),
Self::Planner(e) => Some(e),
Self::Processor(e) => Some(e),
Self::Io(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for AkarError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<StorageError> for AkarError {
fn from(e: StorageError) -> Self {
Self::Storage(e)
}
}
impl From<TransactionError> for AkarError {
fn from(e: TransactionError) -> Self {
Self::Transaction(e)
}
}
impl From<CatalogError> for AkarError {
fn from(e: CatalogError) -> Self {
Self::Catalog(e)
}
}
impl From<BinderError> for AkarError {
fn from(e: BinderError) -> Self {
Self::Binder(e)
}
}
impl From<PlannerError> for AkarError {
fn from(e: PlannerError) -> Self {
Self::Planner(e)
}
}
impl From<ProcessorError> for AkarError {
fn from(e: ProcessorError) -> Self {
Self::Processor(e)
}
}
pub type Result<T> = std::result::Result<T, AkarError>;
#[derive(Debug)]
pub enum StorageError {
Wal(String),
BufferManager(String),
TableNotFound(String),
ColumnNotFound(String),
TypeMismatch { expected: String, actual: String },
Page(String),
ShadowFile(String),
Undo(String),
LocalStorage(String),
Spiller(String),
Index(String),
Reader(String),
}
impl fmt::Display for StorageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Wal(s) => write!(f, "WAL: {s}"),
Self::BufferManager(s) => write!(f, "buffer manager: {s}"),
Self::TableNotFound(s) => write!(f, "table not found: {s}"),
Self::ColumnNotFound(s) => write!(f, "column not found: {s}"),
Self::TypeMismatch { expected, actual } => {
write!(f, "type mismatch: expected {expected}, got {actual}")
}
Self::Page(s) => write!(f, "page: {s}"),
Self::ShadowFile(s) => write!(f, "shadow file: {s}"),
Self::Undo(s) => write!(f, "undo: {s}"),
Self::LocalStorage(s) => write!(f, "local storage: {s}"),
Self::Spiller(s) => write!(f, "spiller: {s}"),
Self::Index(s) => write!(f, "index: {s}"),
Self::Reader(s) => write!(f, "reader: {s}"),
}
}
}
impl std::error::Error for StorageError {}
impl From<StorageError> for String {
fn from(e: StorageError) -> String {
format!("storage: {e}")
}
}
#[derive(Debug)]
pub enum TransactionError {
TableLocked { table_id: u64, owner_txn: u64 },
WriteConflict { table_id: u64, row_id: u64, conflicting_txn: u64 },
ConcurrentWriteDisabled,
ShuttingDown,
NoActiveTransaction,
LockPoisoned(String),
}
impl fmt::Display for TransactionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TableLocked { table_id, owner_txn } => {
write!(f, "table {table_id} already locked by txn#{owner_txn}")
}
Self::WriteConflict { table_id, row_id, conflicting_txn } => {
write!(f, "write conflict on table {table_id} row {row_id}: txn#{conflicting_txn} also modified this row")
}
Self::ConcurrentWriteDisabled => write!(f, "concurrent write not allowed"),
Self::ShuttingDown => write!(f, "transaction manager is shutting down"),
Self::NoActiveTransaction => write!(f, "no active write transaction"),
Self::LockPoisoned(s) => write!(f, "lock poisoned: {s}"),
}
}
}
impl std::error::Error for TransactionError {}
impl From<TransactionError> for String {
fn from(e: TransactionError) -> String {
format!("transaction: {e}")
}
}
#[derive(Debug)]
pub enum CatalogError {
AlreadyExists(String),
NotFound(String),
ColumnAlreadyExists { table: String, column: String },
ColumnNotFound { table: String, column: String },
InvalidOperation(String),
}
impl fmt::Display for CatalogError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AlreadyExists(s) => write!(f, "already exists: {s}"),
Self::NotFound(s) => write!(f, "not found: {s}"),
Self::ColumnAlreadyExists { table, column } => {
write!(f, "column '{column}' already exists on table '{table}'")
}
Self::ColumnNotFound { table, column } => {
write!(f, "column '{column}' not found on table '{table}'")
}
Self::InvalidOperation(s) => write!(f, "invalid operation: {s}"),
}
}
}
impl std::error::Error for CatalogError {}
impl From<CatalogError> for String {
fn from(e: CatalogError) -> String {
format!("catalog: {e}")
}
}
#[derive(Debug)]
pub enum BinderError {
TableNotFound(String),
ColumnNotFound { table: String, column: String },
VariableNotInScope(String),
UnknownType(String),
Validation(String),
Io(String),
}
impl fmt::Display for BinderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TableNotFound(s) => write!(f, "table not found: {s}"),
Self::ColumnNotFound { table, column } => {
write!(f, "column '{column}' not found in table '{table}'")
}
Self::VariableNotInScope(s) => write!(f, "variable not in scope: {s}"),
Self::UnknownType(s) => write!(f, "unknown type: {s}"),
Self::Validation(s) => write!(f, "{s}"),
Self::Io(s) => write!(f, "I/O error: {s}"),
}
}
}
impl std::error::Error for BinderError {}
impl From<BinderError> for String {
fn from(e: BinderError) -> String {
format!("binder: {e}")
}
}
impl From<String> for BinderError {
fn from(s: String) -> Self {
BinderError::Validation(s)
}
}
impl From<&str> for BinderError {
fn from(s: &str) -> Self {
BinderError::Validation(s.to_string())
}
}
impl From<CatalogError> for BinderError {
fn from(e: CatalogError) -> Self {
match e {
CatalogError::AlreadyExists(s) => BinderError::Validation(format!("already exists: {s}")),
CatalogError::NotFound(s) => BinderError::TableNotFound(s),
CatalogError::ColumnAlreadyExists { table, column } => {
BinderError::Validation(format!("column '{column}' already exists on table '{table}'"))
}
CatalogError::ColumnNotFound { table, column } => {
BinderError::ColumnNotFound { table, column }
}
CatalogError::InvalidOperation(s) => BinderError::Validation(s),
}
}
}
#[derive(Debug)]
pub enum PlannerError {
Planning(String),
}
impl fmt::Display for PlannerError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Planning(s) => write!(f, "{s}"),
}
}
}
impl std::error::Error for PlannerError {}
impl From<PlannerError> for String {
fn from(e: PlannerError) -> String {
format!("planner: {e}")
}
}
impl From<String> for PlannerError {
fn from(s: String) -> Self {
PlannerError::Planning(s)
}
}
impl From<&str> for PlannerError {
fn from(s: &str) -> Self {
PlannerError::Planning(s.to_string())
}
}
#[derive(Debug)]
pub enum ProcessorError {
Expression(String),
Execution(String),
Io(String),
}
impl fmt::Display for ProcessorError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Expression(s) => write!(f, "expression: {s}"),
Self::Execution(s) => write!(f, "{s}"),
Self::Io(s) => write!(f, "I/O error: {s}"),
}
}
}
impl std::error::Error for ProcessorError {}
impl From<ProcessorError> for String {
fn from(e: ProcessorError) -> String {
format!("processor: {e}")
}
}
impl From<String> for ProcessorError {
fn from(s: String) -> Self {
ProcessorError::Execution(s)
}
}
impl From<&str> for ProcessorError {
fn from(s: &str) -> Self {
ProcessorError::Execution(s.to_string())
}
}
impl From<StorageError> for ProcessorError {
fn from(e: StorageError) -> Self {
ProcessorError::Execution(format!("storage: {e}"))
}
}
pub fn lock_or_poisoned<T>(mutex: &std::sync::Mutex<T>) -> crate::error::Result<std::sync::MutexGuard<'_, T>> {
mutex
.lock()
.map_err(|e| AkarError::Transaction(TransactionError::LockPoisoned(e.to_string())))
}