use crate::executor::evaluator::VectorError;
use crate::storage::StorageError;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ExecutorError {
#[error("hnsw error: {0}")]
Core(#[from] alopex_core::Error),
#[error("table not found: {0}")]
TableNotFound(String),
#[error("table already exists: {0}")]
TableAlreadyExists(String),
#[error("index not found: {0}")]
IndexNotFound(String),
#[error("index already exists: {0}")]
IndexAlreadyExists(String),
#[error("column not found: {0}")]
ColumnNotFound(String),
#[error("constraint violation: {0}")]
ConstraintViolation(#[from] ConstraintViolation),
#[error("evaluation error: {0}")]
Evaluation(#[from] EvaluationError),
#[error("unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("transaction conflict")]
TransactionConflict,
#[error("read-only transaction: cannot execute {operation}")]
ReadOnlyTransaction { operation: String },
#[error("storage error: {0}")]
Storage(#[from] StorageError),
#[error("column required: {column} (DEFAULT not supported in v0.1.2)")]
ColumnRequired { column: String },
#[error("invalid index name: {name} - {reason}")]
InvalidIndexName { name: String, reason: String },
#[error("invalid operation: {operation} - {reason}")]
InvalidOperation { operation: String, reason: String },
#[error("resource exhausted: {message}")]
ResourceExhausted { message: String },
#[error("file not found: {0}")]
FileNotFound(String),
#[error("path validation failed for '{path}': {reason}")]
PathValidationFailed { path: String, reason: String },
#[error("unsupported format: {0}")]
UnsupportedFormat(String),
#[error("schema mismatch: expected {expected} columns, got {actual} - {reason}")]
SchemaMismatch {
expected: usize,
actual: usize,
reason: String,
},
#[error("invalid storage type: {0}")]
InvalidStorageType(String),
#[error("invalid compression: {0}")]
InvalidCompression(String),
#[error("invalid row_group_size: {0}")]
InvalidRowGroupSize(String),
#[error("invalid rowid_mode: {0}")]
InvalidRowIdMode(String),
#[error("unknown table option: {0}")]
UnknownTableOption(String),
#[error("duplicate option: {0}")]
DuplicateOption(String),
#[error("vector error: {0}")]
Vector(#[from] VectorError),
#[error("bulk load error: {0}")]
BulkLoad(String),
#[error("columnar engine error: {0}")]
Columnar(String),
#[error("planner error: {0}")]
Planner(#[from] crate::planner::PlannerError),
}
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum ConstraintViolation {
#[error("NOT NULL constraint violated on column: {column}")]
NotNull { column: String },
#[error("PRIMARY KEY constraint violated on columns: {columns:?}, value: {value:?}")]
PrimaryKey {
columns: Vec<String>,
value: Option<String>,
},
#[error(
"UNIQUE constraint violated on index: {index_name}, columns: {columns:?}, value: {value:?}"
)]
Unique {
index_name: String,
columns: Vec<String>,
value: Option<String>,
},
}
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum EvaluationError {
#[error("division by zero")]
DivisionByZero,
#[error("integer overflow")]
Overflow,
#[error("type mismatch: expected {expected}, got {actual}")]
TypeMismatch { expected: String, actual: String },
#[error("invalid column reference: index {index}")]
InvalidColumnRef { index: usize },
#[error("unsupported expression: {0}")]
UnsupportedExpression(String),
#[error("unsupported function: {0}")]
UnsupportedFunction(String),
#[error("vector error: {0}")]
Vector(#[from] VectorError),
}
pub type Result<T> = std::result::Result<T, ExecutorError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_executor_error_display() {
let err = ExecutorError::TableNotFound("users".into());
assert_eq!(err.to_string(), "table not found: users");
}
#[test]
fn test_constraint_violation_display() {
let err = ConstraintViolation::NotNull {
column: "name".into(),
};
assert_eq!(
err.to_string(),
"NOT NULL constraint violated on column: name"
);
}
#[test]
fn test_evaluation_error_display() {
let err = EvaluationError::DivisionByZero;
assert_eq!(err.to_string(), "division by zero");
}
#[test]
fn test_constraint_violation_from() {
let violation = ConstraintViolation::NotNull {
column: "age".into(),
};
let err: ExecutorError = violation.into();
assert!(matches!(err, ExecutorError::ConstraintViolation(_)));
}
#[test]
fn test_evaluation_error_from() {
let eval_err = EvaluationError::Overflow;
let err: ExecutorError = eval_err.into();
assert!(matches!(err, ExecutorError::Evaluation(_)));
}
#[test]
fn test_vector_error_conversion() {
let vector_err = VectorError::ZeroNormVector;
let eval_err: EvaluationError = vector_err.clone().into();
assert!(matches!(eval_err, EvaluationError::Vector(_)));
let exec_err: ExecutorError = vector_err.into();
assert!(matches!(exec_err, ExecutorError::Vector(_)));
}
#[test]
fn test_path_validation_failed_display() {
let err = ExecutorError::PathValidationFailed {
path: "/tmp/data.parquet".into(),
reason: "symbolic links not allowed".into(),
};
assert_eq!(
err.to_string(),
"path validation failed for '/tmp/data.parquet': symbolic links not allowed"
);
}
}